"""Notification tracker-target link management API routes."""

import logging
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import BaseModel
from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession

from ..auth.dependencies import get_current_user
from ..database.engine import get_session
from ..database.models import (
    NotificationTarget,
    NotificationTracker,
    NotificationTrackerTarget,
    ServiceProvider,
    TargetReceiver,
    TemplateConfig,
    TemplateSlot,
    TrackingConfig,
    User,
)
from ..services.notifier import send_test_notification
from ..services.manual_dispatch import dispatch_test_notification
from ..services.scheduler import reschedule_immich_dispatch_jobs
from .helpers import get_owned_entity

_LOGGER = logging.getLogger(__name__)

router = APIRouter(prefix="/api/notification-trackers/{tracker_id}/targets", tags=["notification-tracker-targets"])


class NotificationTrackerTargetCreate(BaseModel):
    target_id: int
    tracking_config_id: int | None = None
    template_config_id: int | None = None
    enabled: bool = True
    quiet_hours_start: str | None = None
    quiet_hours_end: str | None = None


class NotificationTrackerTargetUpdate(BaseModel):
    tracking_config_id: int | None = None
    template_config_id: int | None = None
    enabled: bool | None = None
    quiet_hours_start: str | None = None
    quiet_hours_end: str | None = None


@router.get("")
async def list_notification_tracker_targets(
    tracker_id: int,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """List all target links for a notification tracker."""
    await _get_user_tracker(session, tracker_id, user.id)
    result = await session.exec(
        select(NotificationTrackerTarget).where(NotificationTrackerTarget.tracker_id == tracker_id)
    )
    return [await _tt_response(session, tt) for tt in result.all()]


@router.post("", status_code=status.HTTP_201_CREATED)
async def create_notification_tracker_target(
    tracker_id: int,
    body: NotificationTrackerTargetCreate,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Link a target to a notification tracker with per-link configuration."""
    tracker = await _get_user_tracker(session, tracker_id, user.id)

    # Validate target exists and belongs to user
    target = await session.get(NotificationTarget, body.target_id)
    if not target or target.user_id != user.id:
        raise HTTPException(status_code=404, detail="Target not found")

    # Check for duplicate link
    result = await session.exec(
        select(NotificationTrackerTarget).where(
            NotificationTrackerTarget.tracker_id == tracker_id,
            NotificationTrackerTarget.target_id == body.target_id,
        )
    )
    if result.first():
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Target is already linked to this tracker",
        )

    # Resolve tracker's provider type for config validation
    provider = await session.get(ServiceProvider, tracker.provider_id)
    if not provider:
        raise HTTPException(status_code=404, detail="Provider not found")

    # Validate config ownership + provider type match
    if body.tracking_config_id:
        tc = await session.get(TrackingConfig, body.tracking_config_id)
        if not tc or (tc.user_id != user.id and tc.user_id != 0):
            raise HTTPException(status_code=404, detail="Tracking config not found")
        if tc.provider_type != provider.type:
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                detail=f"Tracking config provider type '{tc.provider_type}' does not match tracker provider '{provider.type}'",
            )
    if body.template_config_id:
        tpc = await session.get(TemplateConfig, body.template_config_id)
        if not tpc or (tpc.user_id != user.id and tpc.user_id != 0):
            raise HTTPException(status_code=404, detail="Template config not found")
        if tpc.provider_type != provider.type:
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                detail=f"Template config provider type '{tpc.provider_type}' does not match tracker provider '{provider.type}'",
            )

    tt = NotificationTrackerTarget(tracker_id=tracker_id, **body.model_dump())
    session.add(tt)
    await session.commit()
    await session.refresh(tt)
    await reschedule_immich_dispatch_jobs()
    return await _tt_response(session, tt)


@router.put("/{tracker_target_id}")
async def update_notification_tracker_target(
    tracker_id: int,
    tracker_target_id: int,
    body: NotificationTrackerTargetUpdate,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Update a notification tracker-target link's configuration."""
    tracker = await _get_user_tracker(session, tracker_id, user.id)
    tt = await session.get(NotificationTrackerTarget, tracker_target_id)
    if not tt or tt.tracker_id != tracker_id:
        raise HTTPException(status_code=404, detail="Tracker-target link not found")
    provider = await session.get(ServiceProvider, tracker.provider_id)
    if not provider:
        raise HTTPException(status_code=404, detail="Provider not found")

    updates = body.model_dump(exclude_unset=True)
    # Validate config ownership + provider type match if being changed
    if "tracking_config_id" in updates and updates["tracking_config_id"]:
        tc = await session.get(TrackingConfig, updates["tracking_config_id"])
        if not tc or (tc.user_id != user.id and tc.user_id != 0):
            raise HTTPException(status_code=404, detail="Tracking config not found")
        if tc.provider_type != provider.type:
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                detail=f"Tracking config provider type '{tc.provider_type}' does not match tracker provider '{provider.type}'",
            )
    if "template_config_id" in updates and updates["template_config_id"]:
        tpc = await session.get(TemplateConfig, updates["template_config_id"])
        if not tpc or (tpc.user_id != user.id and tpc.user_id != 0):
            raise HTTPException(status_code=404, detail="Template config not found")
        if tpc.provider_type != provider.type:
            raise HTTPException(
                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
                detail=f"Template config provider type '{tpc.provider_type}' does not match tracker provider '{provider.type}'",
            )

    for field, value in updates.items():
        setattr(tt, field, value)
    session.add(tt)
    await session.commit()
    await session.refresh(tt)
    await reschedule_immich_dispatch_jobs()
    return await _tt_response(session, tt)


@router.delete("/{tracker_target_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_notification_tracker_target(
    tracker_id: int,
    tracker_target_id: int,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Remove a target link from a notification tracker."""
    await _get_user_tracker(session, tracker_id, user.id)
    tt = await session.get(NotificationTrackerTarget, tracker_target_id)
    if not tt or tt.tracker_id != tracker_id:
        raise HTTPException(status_code=404, detail="Tracker-target link not found")
    await session.delete(tt)
    await session.commit()
    await reschedule_immich_dispatch_jobs()


@router.post("/{tracker_target_id}/test/{test_type}")
async def test_notification_tracker_target(
    tracker_id: int,
    tracker_target_id: int,
    test_type: str,
    locale: str = Query("en"),
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Send a test notification using real provider data.

    test_type: basic | periodic | scheduled | memory
    """
    valid_types = {"basic", "periodic", "scheduled", "memory"}
    if test_type not in valid_types:
        raise HTTPException(status_code=400, detail=f"Invalid test type. Must be one of: {', '.join(valid_types)}")

    tracker = await _get_user_tracker(session, tracker_id, user.id)
    tt = await session.get(NotificationTrackerTarget, tracker_target_id)
    if not tt or tt.tracker_id != tracker_id:
        raise HTTPException(status_code=404, detail="Tracker-target link not found")

    target = await session.get(NotificationTarget, tt.target_id)
    if not target:
        raise HTTPException(status_code=404, detail="Target not found")

    # Resolve effective locale from first receiver (explicit locale → TelegramChat lang)
    effective_locale = locale
    recv_result = await session.exec(
        select(TargetReceiver).where(
            TargetReceiver.target_id == target.id,
            TargetReceiver.enabled == True,
        )
    )
    first_recv = recv_result.first()
    if first_recv:
        recv_locale = getattr(first_recv, 'locale', '') or ''
        if not recv_locale and target.type == "telegram":
            # Resolve from TelegramChat language_override/language_code
            from ..database.models import TelegramBot, TelegramChat
            chat_id = str(first_recv.config.get("chat_id", ""))
            bot_id = target.config.get("bot_id")
            if chat_id and bot_id:
                chat_row = (await session.exec(
                    select(TelegramChat).where(
                        TelegramChat.bot_id == bot_id,
                        TelegramChat.chat_id == chat_id,
                    )
                )).first()
                if chat_row:
                    recv_locale = (
                        getattr(chat_row, 'language_override', '') or
                        getattr(chat_row, 'language_code', '') or ''
                    )
        if recv_locale:
            effective_locale = recv_locale[:2].lower()

    if test_type == "basic":
        r = await send_test_notification(target, locale=effective_locale)
        return {"target": target.name, **r}

    # For periodic/scheduled/memory — dispatch through the real NotificationDispatcher
    r = await dispatch_test_notification(
        session=session,
        tracker=tracker,
        tt=tt,
        target=target,
        test_type=test_type,
        locale=effective_locale,
    )
    return {"target": target.name, **r}


async def _tt_response(session: AsyncSession, tt: NotificationTrackerTarget) -> dict:
    """Build tracker-target response with target details."""
    target = await session.get(NotificationTarget, tt.target_id)
    return {
        "id": tt.id,
        "tracker_id": tt.tracker_id,
        "target_id": tt.target_id,
        "target_name": target.name if target else None,
        "target_type": target.type if target else None,
        "target_icon": target.icon if target else None,
        "tracking_config_id": tt.tracking_config_id,
        "template_config_id": tt.template_config_id,
        "enabled": tt.enabled,
        "quiet_hours_start": tt.quiet_hours_start,
        "quiet_hours_end": tt.quiet_hours_end,
        "created_at": tt.created_at.isoformat(),
    }


async def _get_user_tracker(
    session: AsyncSession, tracker_id: int, user_id: int
) -> NotificationTracker:
    return await get_owned_entity(
        session, NotificationTracker, tracker_id, user_id,
        not_found_msg="Tracker not found",
    )
