"""Avatar service — fetches deterministic face photos from randomuser.me"""

import asyncio
from pathlib import Path

import httpx

AVATAR_DIR = Path(__file__).parent.parent.parent / "data" / "avatars"


class AvatarService:
    def __init__(self):
        self._client: httpx.AsyncClient | None = None
        AVATAR_DIR.mkdir(parents=True, exist_ok=True)

    @property
    def client(self) -> httpx.AsyncClient:
        if self._client is None or self._client.is_closed:
            self._client = httpx.AsyncClient(timeout=10.0)
        return self._client

    def get_path(self, name: str) -> Path | None:
        path = AVATAR_DIR / f"{name}.jpg"
        return path if path.exists() else None

    async def get_or_fetch(self, name: str, gender: str = "male") -> Path:
        """Get cached avatar or fetch from randomuser.me. Returns file path."""
        g = "female" if gender.lower().startswith("f") else "male"
        path = AVATAR_DIR / f"{name}.jpg"
        # Check for gender mismatch marker — re-fetch if gender changed
        marker = AVATAR_DIR / f"{name}.gender"
        if path.exists():
            cached_gender = marker.read_text().strip() if marker.exists() else None
            if cached_gender == g:
                return path
            # Gender mismatch or no marker — re-fetch
            path.unlink(missing_ok=True)

        try:
            seed = f"{name.lower().replace(' ', '_')}_{g}"
            resp = await self.client.get(
                "https://randomuser.me/api/",
                params={"gender": g, "seed": seed},
                timeout=8.0,
            )
            resp.raise_for_status()
            data = resp.json()
            photo_url = data["results"][0]["picture"]["large"]

            photo_resp = await self.client.get(photo_url, timeout=8.0)
            photo_resp.raise_for_status()

            path.write_bytes(photo_resp.content)
            marker.write_text(g)
            print(f"[Avatar] Fetched avatar for {name} ({g})")
            return path
        except Exception as e:
            print(f"[Avatar] Failed to fetch for {name}: {e}")
            raise

    async def prefetch_batch(self, callers: list[dict]):
        """Fetch avatars for multiple callers in parallel.
        Each dict should have 'name' and 'gender' keys."""
        tasks = []
        for caller in callers:
            name = caller.get("name", "")
            gender = caller.get("gender", "male")
            if not name:
                continue
            g = "female" if gender.lower().startswith("f") else "male"
            path = AVATAR_DIR / f"{name}.jpg"
            marker = AVATAR_DIR / f"{name}.gender"
            # Always call get_or_fetch if: no file, no gender marker, or gender mismatch
            if not path.exists() or not marker.exists() or marker.read_text().strip() != g:
                if path.exists():
                    print(f"[Avatar] Gender mismatch for {name}: cached={marker.read_text().strip() if marker.exists() else '?'}, want={g} — re-fetching")
                tasks.append(self.get_or_fetch(name, gender))

        if not tasks:
            return

        results = await asyncio.gather(*tasks, return_exceptions=True)
        fetched = sum(1 for r in results if not isinstance(r, Exception))
        failed = sum(1 for r in results if isinstance(r, Exception))
        if fetched:
            print(f"[Avatar] Pre-fetched {fetched} avatars{f', {failed} failed' if failed else ''}")

    async def ensure_devon(self):
        """Pre-fetch Devon's avatar on startup."""
        try:
            await self.get_or_fetch("Devon", "male")
        except Exception:
            pass


avatar_service = AvatarService()
