"""Immich-specific data models."""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any

from .constants import ASSET_TYPE_IMAGE, ASSET_TYPE_VIDEO

_LOGGER = logging.getLogger(__name__)


@dataclass
class SharedLinkInfo:
    """Shared link information from Immich."""

    id: str
    key: str
    has_password: bool = False
    password: str | None = None
    expires_at: datetime | None = None
    allow_download: bool = True
    show_metadata: bool = True

    @property
    def is_expired(self) -> bool:
        if self.expires_at is None:
            return False
        return datetime.now(self.expires_at.tzinfo) > self.expires_at

    @property
    def is_accessible(self) -> bool:
        return not self.has_password and not self.is_expired

    @classmethod
    def from_api_response(cls, data: dict[str, Any]) -> SharedLinkInfo:
        expires_at = None
        if data.get("expiresAt"):
            try:
                expires_at = datetime.fromisoformat(
                    data["expiresAt"].replace("Z", "+00:00")
                )
            except ValueError:
                pass

        password = data.get("password")
        return cls(
            id=data["id"],
            key=data["key"],
            has_password=bool(password),
            password=password if password else None,
            expires_at=expires_at,
            allow_download=data.get("allowDownload", True),
            show_metadata=data.get("showMetadata", True),
        )


@dataclass
class ImmichAssetInfo:
    """Immich asset with full detail from API."""

    id: str
    type: str  # IMAGE or VIDEO
    filename: str
    created_at: str
    owner_id: str = ""
    owner_name: str = ""
    description: str = ""
    people: list[str] = field(default_factory=list)
    is_favorite: bool = False
    rating: int | None = None
    latitude: float | None = None
    longitude: float | None = None
    city: str | None = None
    state: str | None = None
    country: str | None = None
    file_size: int | None = None  # bytes, from exifInfo.fileSizeInByte
    is_processed: bool = True
    thumbhash: str | None = None

    @classmethod
    def from_api_response(
        cls, data: dict[str, Any], users_cache: dict[str, str] | None = None
    ) -> ImmichAssetInfo:
        people = []
        if "people" in data:
            people = [p.get("name", "") for p in data["people"] if p.get("name")]

        owner_id = data.get("ownerId", "")
        owner_name = ""
        if users_cache and owner_id:
            owner_name = users_cache.get(owner_id, "")

        description = data.get("description", "") or ""
        exif_info = data.get("exifInfo")
        if not description and exif_info:
            description = exif_info.get("description", "") or ""

        is_favorite = data.get("isFavorite", False)
        rating = exif_info.get("rating") if exif_info else None

        latitude = exif_info.get("latitude") if exif_info else None
        longitude = exif_info.get("longitude") if exif_info else None
        city = exif_info.get("city") if exif_info else None
        state = exif_info.get("state") if exif_info else None
        country = exif_info.get("country") if exif_info else None
        file_size = exif_info.get("fileSizeInByte") if exif_info else None

        asset_type = data.get("type", ASSET_TYPE_IMAGE)
        is_processed = cls._check_processing_status(data)
        thumbhash = data.get("thumbhash")

        return cls(
            id=data["id"],
            type=asset_type,
            filename=data.get("originalFileName", ""),
            created_at=data.get("fileCreatedAt", ""),
            owner_id=owner_id,
            owner_name=owner_name,
            description=description,
            people=people,
            is_favorite=is_favorite,
            rating=rating,
            latitude=latitude,
            longitude=longitude,
            city=city,
            state=state,
            country=country,
            file_size=file_size,
            is_processed=is_processed,
            thumbhash=thumbhash,
        )

    @staticmethod
    def _check_processing_status(data: dict[str, Any]) -> bool:
        is_offline = data.get("isOffline", False)
        is_trashed = data.get("isTrashed", False)
        is_archived = data.get("isArchived", False)
        thumbhash = data.get("thumbhash")

        if is_offline or is_trashed or is_archived:
            return False

        return bool(thumbhash)


@dataclass(frozen=True)
class ImmichAlbumMeta:
    """Lightweight album metadata from ``GET /api/albums/{id}?withoutAssets=true``.

    Used as a cheap change-detection probe so we can skip the multi-MB
    full-asset fetch when nothing interesting has changed. Large albums
    (tens to hundreds of thousands of assets) would otherwise re-serialize
    the entire asset list on every poll interval.
    """

    id: str
    name: str
    asset_count: int
    updated_at: str
    shared: bool
    thumbnail_asset_id: str | None = None

    @classmethod
    def from_api_response(cls, data: dict[str, Any]) -> ImmichAlbumMeta:
        return cls(
            id=data["id"],
            name=data.get("albumName", "Unnamed"),
            asset_count=int(data.get("assetCount", 0) or 0),
            updated_at=data.get("updatedAt", "") or "",
            shared=bool(data.get("shared", False)),
            thumbnail_asset_id=data.get("albumThumbnailAssetId"),
        )

    def fingerprint(self) -> dict[str, Any]:
        """Return a minimal serializable dict for persistence + equality checks.

        We purposefully exclude ``id`` (known from the state row) and keep the
        dict flat so JSON round-trips are cheap and stable for equality.
        """
        return {
            "updated_at": self.updated_at,
            "asset_count": self.asset_count,
            "shared": self.shared,
            "name": self.name,
            "thumbnail_asset_id": self.thumbnail_asset_id or "",
        }


@dataclass
class ImmichAlbumData:
    """Full album data from Immich API."""

    id: str
    name: str
    asset_count: int
    photo_count: int
    video_count: int
    created_at: str
    updated_at: str
    shared: bool
    owner: str
    thumbnail_asset_id: str | None
    asset_ids: set[str] = field(default_factory=set)
    assets: dict[str, ImmichAssetInfo] = field(default_factory=dict)
    people: set[str] = field(default_factory=set)

    @classmethod
    def from_api_response(
        cls, data: dict[str, Any], users_cache: dict[str, str] | None = None
    ) -> ImmichAlbumData:
        assets_data = data.get("assets", [])
        asset_ids = set()
        assets = {}
        people = set()
        photo_count = 0
        video_count = 0

        for asset_data in assets_data:
            asset = ImmichAssetInfo.from_api_response(asset_data, users_cache)
            if not asset.is_processed:
                continue
            asset_ids.add(asset.id)
            assets[asset.id] = asset
            people.update(asset.people)
            if asset.type == ASSET_TYPE_IMAGE:
                photo_count += 1
            elif asset.type == ASSET_TYPE_VIDEO:
                video_count += 1

        return cls(
            id=data["id"],
            name=data.get("albumName", "Unnamed"),
            asset_count=data.get("assetCount", len(asset_ids)),
            photo_count=photo_count,
            video_count=video_count,
            created_at=data.get("createdAt", ""),
            updated_at=data.get("updatedAt", ""),
            shared=data.get("shared", False),
            owner=data.get("owner", {}).get("name", "Unknown"),
            thumbnail_asset_id=data.get("albumThumbnailAssetId"),
            asset_ids=asset_ids,
            assets=assets,
            people=people,
        )
