"""Google Photos album change detection — produces generic ServiceEvent objects."""

from __future__ import annotations

import logging
from datetime import datetime, timezone

from notify_bridge_core.models.events import EventType, ServiceEvent
from notify_bridge_core.models.media import MediaAsset, MediaType
from notify_bridge_core.providers.base import ServiceProviderType

from .constants import CACHE_HOST, PHOTO_DOWNLOAD_SUFFIX, PHOTO_THUMBNAIL_SUFFIX, VIDEO_DOWNLOAD_SUFFIX
from .models import GooglePhotosAlbumData, GooglePhotosMediaItem

_LOGGER = logging.getLogger(__name__)


def _asset_to_media(item: GooglePhotosMediaItem) -> MediaAsset:
    """Convert GooglePhotosMediaItem to generic MediaAsset."""
    media_type = MediaType.VIDEO if item.is_video else MediaType.IMAGE

    try:
        created_at = datetime.fromisoformat(item.created_at.replace("Z", "+00:00"))
    except (ValueError, AttributeError):
        created_at = datetime.now(timezone.utc)

    if item.is_video:
        full_url = f"{item.base_url}{VIDEO_DOWNLOAD_SUFFIX}" if item.base_url else ""
        thumbnail_url = f"{item.base_url}{PHOTO_THUMBNAIL_SUFFIX}" if item.base_url else ""
    else:
        full_url = f"{item.base_url}{PHOTO_DOWNLOAD_SUFFIX}" if item.base_url else ""
        thumbnail_url = f"{item.base_url}{PHOTO_THUMBNAIL_SUFFIX}" if item.base_url else ""

    return MediaAsset(
        id=item.id,
        type=media_type,
        filename=item.filename,
        created_at=created_at,
        description=item.description or None,
        thumbnail_url=thumbnail_url,
        preview_url=full_url,  # Google Photos: transcoded via size suffix, same as full
        full_url=full_url,
        extra={
            "google_photos_media_id": item.id,
            "product_url": item.product_url,
            "mime_type": item.mime_type,
            "width": item.width,
            "height": item.height,
            "cache_key": f"{CACHE_HOST}:{item.id}",
        },
    )


def _make_base_extra(album: GooglePhotosAlbumData) -> dict:
    """Build common extra dict for album events."""
    return {
        "album_url": album.product_url,
        "shared": album.is_shared,
        "photo_count": album.photo_count,
        "video_count": album.video_count,
        "asset_count": album.asset_count,
    }


def detect_album_changes(
    old_album: GooglePhotosAlbumData,
    new_album: GooglePhotosAlbumData,
    pending_asset_ids: set[str],
    provider_name: str,
) -> tuple[list[ServiceEvent], set[str]]:
    """Detect changes between two album states, producing generic ServiceEvents.

    Args:
        old_album: Previous album data.
        new_album: Current album data.
        pending_asset_ids: Assets detected but not yet fully processed.
        provider_name: Name of the provider instance.

    Returns:
        Tuple of (list of ServiceEvents, updated pending_asset_ids).
    """
    added_ids = new_album.asset_ids - old_album.asset_ids
    removed_ids = old_album.asset_ids - new_album.asset_ids

    pending = set(pending_asset_ids)

    # Collect newly added processed assets
    added_assets: list[GooglePhotosMediaItem] = []
    for aid in added_ids:
        if aid not in new_album.assets:
            continue
        asset = new_album.assets[aid]
        if asset.is_processed:
            added_assets.append(asset)
        else:
            pending.add(aid)

    # Check if pending assets are now processed
    for aid in list(pending):
        if aid not in new_album.assets:
            pending.discard(aid)
            continue
        asset = new_album.assets[aid]
        if asset.is_processed:
            added_assets.append(asset)
            pending.discard(aid)

    # Detect metadata changes
    name_changed = old_album.name != new_album.name
    sharing_changed = old_album.is_shared != new_album.is_shared

    if not added_assets and not removed_ids and not name_changed and not sharing_changed:
        return [], pending

    now = datetime.now(timezone.utc)
    extra = _make_base_extra(new_album)
    events: list[ServiceEvent] = []

    if added_assets:
        media_assets = [_asset_to_media(a) for a in added_assets]
        events.append(ServiceEvent(
            event_type=EventType.ASSETS_ADDED,
            provider_type=ServiceProviderType.GOOGLE_PHOTOS,
            provider_name=provider_name,
            collection_id=new_album.id,
            collection_name=new_album.name,
            timestamp=now,
            added_assets=media_assets,
            removed_asset_ids=[],
            added_count=len(added_assets),
            removed_count=0,
            extra=dict(extra),
        ))

    if removed_ids:
        events.append(ServiceEvent(
            event_type=EventType.ASSETS_REMOVED,
            provider_type=ServiceProviderType.GOOGLE_PHOTOS,
            provider_name=provider_name,
            collection_id=new_album.id,
            collection_name=new_album.name,
            timestamp=now,
            added_assets=[],
            removed_asset_ids=list(removed_ids),
            added_count=0,
            removed_count=len(removed_ids),
            extra=dict(extra),
        ))

    if name_changed:
        events.append(ServiceEvent(
            event_type=EventType.COLLECTION_RENAMED,
            provider_type=ServiceProviderType.GOOGLE_PHOTOS,
            provider_name=provider_name,
            collection_id=new_album.id,
            collection_name=new_album.name,
            timestamp=now,
            added_assets=[],
            removed_asset_ids=[],
            added_count=0,
            removed_count=0,
            old_name=old_album.name,
            new_name=new_album.name,
            extra=dict(extra),
        ))

    if sharing_changed:
        events.append(ServiceEvent(
            event_type=EventType.SHARING_CHANGED,
            provider_type=ServiceProviderType.GOOGLE_PHOTOS,
            provider_name=provider_name,
            collection_id=new_album.id,
            collection_name=new_album.name,
            timestamp=now,
            added_assets=[],
            removed_asset_ids=[],
            added_count=0,
            removed_count=0,
            old_shared=old_album.is_shared,
            new_shared=new_album.is_shared,
            extra=dict(extra),
        ))

    return events, pending
