"""Photos widget: composes one photo from Immich into the widget's own
region -- the widget-system analogue of routers/device.py's old
_render_photos_mode/_advance_photos_mode/_back_photos_mode, and
app/photo_queue.py's real client.

render() never raises -- an Immich hiccup for this one widget shouldn't
take down the whole panel's render just because one region out of
several couldn't be composed this cycle; it falls back to a small
placeholder instead, the same resilience calendar mode's old photo-inlay
already had (see routers/device.py's `except HTTPException: pass` around
its own inlay fetch)."""

from __future__ import annotations

from fastapi import HTTPException
from PIL import Image
from sqlalchemy.orm import Session

from .. import photo_queue, quiet_hours
from ..db import widget_locked
from ..image_pipeline import compose_into
from ..models import Frame, PhotoWidgetConfig, Widget
from ..routers.common import fetch_source_and_faces, immich_client_for, list_assets
from ._shared import placeholder_image

ACTION_LABELS = {"advance": "Next photo", "back": "Previous photo"}


def render(db: Session, frame: Frame, widget: Widget, target_w: int, target_h: int,
          is_normal_wake: bool = True) -> Image.Image:
    """is_normal_wake is unused here -- photos mode's advance timing is
    already fully idempotent via get_current()'s own elapsed-time check,
    unlike calendar mode's browse_offset (see app/widgets/calendar.py's
    render()). Accepted anyway so every widget type's render() shares one
    call signature regardless of which ones actually care."""
    cfg = db.get(PhotoWidgetConfig, widget.id)
    if not cfg.album_id:
        return placeholder_image(target_w, target_h, ["Photos widget", "not configured yet"])

    try:
        client = immich_client_for(frame)
        assets = list_assets(client, cfg.album_id)
        with widget_locked(db, frame.id, widget.id) as (locked_frame, _, locked_cfg):
            photo_queue.get_current(locked_cfg, assets, locked_frame,
                                    in_quiet_hours=quiet_hours.in_quiet_hours(locked_frame))
            asset_id = locked_cfg.current_asset_id
        if not asset_id:
            return placeholder_image(target_w, target_h, ["No photos available"])
        source, faces = fetch_source_and_faces(client, cfg.display_mode, asset_id)
    except HTTPException as e:
        return placeholder_image(target_w, target_h, ["Photos widget", str(e.detail)[:40]])

    return compose_into(source, faces, target_w, target_h, cfg.display_mode)


def _advance(db: Session, frame: Frame, widget: Widget) -> None:
    cfg = db.get(PhotoWidgetConfig, widget.id)
    if not cfg.album_id:
        return
    try:
        client = immich_client_for(frame)
        assets = list_assets(client, cfg.album_id)
    except HTTPException:
        return  # nothing to advance to this cycle -- next button press tries again
    with widget_locked(db, frame.id, widget.id) as (locked_frame, _, locked_cfg):
        photo_queue.advance_forced(locked_cfg, assets, locked_frame)


def _back(db: Session, frame: Frame, widget: Widget) -> None:
    cfg = db.get(PhotoWidgetConfig, widget.id)
    if not cfg.album_id:
        return
    try:
        client = immich_client_for(frame)
        assets = list_assets(client, cfg.album_id)
    except HTTPException:
        return
    with widget_locked(db, frame.id, widget.id) as (locked_frame, _, locked_cfg):
        photo_queue.back_forced(locked_cfg, assets, locked_frame)


ACTIONS = {"advance": _advance, "back": _back}
