"""Read the local OS/user profile avatar for Connect device cards."""

from __future__ import annotations

import base64
import hashlib
import os
import platform
import re
from pathlib import Path

MAX_SOURCE_BYTES = 512 * 1024
MAX_PAYLOAD_BYTES = 256 * 1024
THUMBNAIL_SIZE = 256

_IMAGE_SUFFIXES = (".png", ".jpg", ".jpeg", ".webp", ".gif", ".bmp")


def _username() -> str:
    for key in ("LOGNAME", "USER", "USERNAME"):
        value = str(os.environ.get(key) or "").strip()
        if value:
            return value
    try:
        import getpass

        return str(getpass.getuser() or "").strip()
    except Exception:
        return ""


def _home_dir() -> Path | None:
    home = str(os.environ.get("HOME") or os.environ.get("USERPROFILE") or "").strip()
    if not home:
        return None
    path = Path(home)
    return path if path.is_dir() else None


def _newest_existing(paths: list[Path]) -> Path | None:
    candidates: list[Path] = []
    for path in paths:
        if path.is_file():
            candidates.append(path)
            continue
        if path.is_dir():
            for child in path.iterdir():
                if child.is_file() and child.suffix.lower() in _IMAGE_SUFFIXES:
                    candidates.append(child)
    if not candidates:
        return None
    return max(candidates, key=lambda item: item.stat().st_mtime)


def _linux_avatar_candidates() -> list[Path]:
    home = _home_dir()
    username = _username()
    paths: list[Path] = []
    if home is not None:
        paths.extend(
            [
                home / ".face",
                home / ".face.icon",
                home / ".face.png",
                home / ".gnome2" / "photo",
            ]
        )
    if username:
        paths.extend(
            [
                Path("/var/lib/AccountsService/icons") / username,
                Path(f"/var/lib/AccountsService/icons/{username}.png"),
                Path(f"/var/lib/AccountsService/icons/{username}.jpg"),
            ]
        )
    return paths


def _windows_avatar_candidates() -> list[Path]:
    appdata = str(os.environ.get("APPDATA") or "").strip()
    if not appdata:
        return []
    account_dir = Path(appdata) / "Microsoft" / "Windows" / "AccountPictures"
    return [account_dir]


def _macos_avatar_candidates() -> list[Path]:
    home = _home_dir()
    if home is None:
        return []
    return [
        home / "Library" / "Images" / "iChat Recent Pictures",
        home / "Pictures" / "Profile Picture.jpg",
    ]


def discover_local_profile_avatar_path() -> Path | None:
    system = (platform.system() or "").strip().lower()
    if system == "linux":
        return _newest_existing(_linux_avatar_candidates())
    if system == "windows":
        return _newest_existing(_windows_avatar_candidates())
    if system == "darwin":
        return _newest_existing(_macos_avatar_candidates())
    return None


def _resize_image_bytes(data: bytes) -> bytes | None:
    try:
        from PIL import Image, ImageOps  # type: ignore
    except Exception:
        return data if len(data) <= MAX_PAYLOAD_BYTES else None

    try:
        import io

        with Image.open(io.BytesIO(data)) as image:
            image = ImageOps.exif_transpose(image)
            if image.mode not in {"RGB", "L"}:
                image = image.convert("RGB")
            image.thumbnail((THUMBNAIL_SIZE, THUMBNAIL_SIZE), Image.Resampling.LANCZOS)
            out = io.BytesIO()
            image.save(out, format="JPEG", quality=85, optimize=True)
            payload = out.getvalue()
    except Exception:
        return None

    if not payload or len(payload) > MAX_PAYLOAD_BYTES:
        return None
    return payload


def read_local_profile_avatar_bytes() -> tuple[bytes, str] | None:
    path = discover_local_profile_avatar_path()
    if path is None:
        return None
    try:
        raw = path.read_bytes()
    except OSError:
        return None
    if not raw or len(raw) > MAX_SOURCE_BYTES:
        return None

    normalized = _resize_image_bytes(raw)
    if normalized is None:
        return None

    ext = path.suffix.lower()
    mime = "image/jpeg"
    if ext == ".png":
        mime = "image/png"
    elif ext == ".webp":
        mime = "image/webp"
    elif ext == ".gif":
        mime = "image/gif"
    return normalized, mime


def build_avatar_upload_payload() -> dict[str, str] | None:
    payload = read_local_profile_avatar_bytes()
    if payload is None:
        return None
    data, _mime = payload
    digest = hashlib.sha256(data).hexdigest()
    encoded = base64.b64encode(data).decode("ascii")
    if len(encoded) > 400_000:
        return None
    return {
        "avatar_base64": encoded,
        "avatar_sha256": digest,
    }


def avatar_payload_changed(last_sha256: str | None) -> bool:
    payload = build_avatar_upload_payload()
    if payload is None:
        return False
    current = str(payload.get("avatar_sha256") or "")
    if not current:
        return False
    return current != str(last_sha256 or "")
