"""Avatar unlockables mixin for TaskMateCoordinator.

Parents define a catalog of avatars, each gated behind a requirement (a level,
a lifetime-points total, or a best-streak length — or ``free`` for always
available). Children unlock avatars by hitting those milestones and can switch
to any avatar they've unlocked; parents can set any catalogue avatar.
"""

from __future__ import annotations

import logging

_LOGGER = logging.getLogger(__name__)

# Shipped defaults so the feature is useful out of the box. Parents can replace
# the whole list from the panel.
DEFAULT_AVATAR_CATALOG: list[dict] = [
    {"id": "starter", "label": "Starter", "icon": "mdi:account-circle", "unlock_type": "free", "unlock_value": 0},
    {"id": "rocket", "label": "Rocket", "icon": "mdi:rocket-launch", "unlock_type": "level", "unlock_value": 3},
    {"id": "robot", "label": "Robot", "icon": "mdi:robot-happy", "unlock_type": "level", "unlock_value": 5},
    {"id": "ninja", "label": "Ninja", "icon": "mdi:ninja", "unlock_type": "level", "unlock_value": 10},
    {"id": "crown", "label": "Royalty", "icon": "mdi:crown", "unlock_type": "points", "unlock_value": 500},
    {"id": "trophy", "label": "Champion", "icon": "mdi:trophy", "unlock_type": "points", "unlock_value": 1000},
    {"id": "fire", "label": "On Fire", "icon": "mdi:fire", "unlock_type": "streak", "unlock_value": 7},
    {"id": "diamond", "label": "Diamond", "icon": "mdi:diamond-stone", "unlock_type": "streak", "unlock_value": 30},
]


class AvatarsMixin:
    """Mixin providing the avatar catalogue and unlock/selection logic."""

    def avatar_catalog(self) -> list[dict]:
        """The configured avatar catalogue (falls back to the shipped default)."""
        raw = self.storage.get_setting("avatar_catalog", None)
        if isinstance(raw, list) and raw:
            return [a for a in raw if isinstance(a, dict) and a.get("icon")]
        return list(DEFAULT_AVATAR_CATALOG)

    def _avatar_unlocked(self, entry: dict, child) -> bool:
        kind = entry.get("unlock_type", "free")
        try:
            value = int(entry.get("unlock_value", 0) or 0)
        except (ValueError, TypeError):
            value = 0
        if kind == "free":
            return True
        if kind == "level":
            return int(self.level_info(child)["level"]) >= value
        if kind == "points":
            return int(getattr(child, "total_points_earned", 0) or 0) >= value
        if kind == "streak":
            return int(getattr(child, "best_streak", 0) or 0) >= value
        return False

    def avatar_options_for_child(self, child) -> list[dict]:
        """Catalogue annotated with per-child unlock state (for sensors/cards)."""
        out: list[dict] = []
        for entry in self.avatar_catalog():
            kind = entry.get("unlock_type", "free")
            value = entry.get("unlock_value", 0)
            if kind == "free":
                req = ""
            elif kind == "level":
                req = f"Level {value}"
            elif kind == "points":
                req = f"{value} earned"
            elif kind == "streak":
                req = f"{value}-day streak"
            else:
                req = ""
            out.append(
                {
                    "id": entry.get("id", entry.get("icon")),
                    "label": entry.get("label", ""),
                    "icon": entry.get("icon"),
                    "unlocked": self._avatar_unlocked(entry, child),
                    "requirement": req,
                }
            )
        return out

    async def async_update_avatar_catalog(self, catalog: list[dict]) -> None:
        """Replace the avatar catalogue (admin)."""
        cleaned: list[dict] = []
        for a in catalog:
            icon = (a.get("icon") or "").strip()
            if not icon:
                continue
            cleaned.append(
                {
                    "id": (a.get("id") or icon).strip(),
                    "label": (a.get("label") or "").strip(),
                    "icon": icon,
                    "unlock_type": a.get("unlock_type", "free"),
                    "unlock_value": int(a.get("unlock_value", 0) or 0),
                }
            )
        self.storage.set_setting("avatar_catalog", cleaned)
        await self.storage.async_save()
        await self.async_refresh()

    async def async_set_avatar(self, child_id: str, icon: str, enforce_unlock: bool = True) -> None:
        """Set a child's avatar.

        When ``enforce_unlock`` (child self-service) the icon must be an
        unlocked catalogue avatar; parents may set any catalogue avatar.
        """
        child = self.get_child(child_id)
        if not child:
            raise ValueError(f"Child {child_id} not found")
        catalog = self.avatar_catalog()
        entry = next((a for a in catalog if a.get("icon") == icon or a.get("id") == icon), None)
        if not entry:
            raise ValueError("That avatar is not in the catalogue")
        if enforce_unlock and not self._avatar_unlocked(entry, child):
            raise ValueError("That avatar is not unlocked yet")
        child.avatar = entry.get("icon")
        self.storage.update_child(child)
        await self.storage.async_save()
        await self.async_refresh()
