"""Target receiver management API routes (nested under targets)."""

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, TargetReceiver, User
from ..services.notifier import (
    _get_test_message,
    resolve_telegram_chat_locale,
    send_to_receiver,
)
from .helpers import get_owned_entity

_LOGGER = logging.getLogger(__name__)

router = APIRouter(prefix="/api/targets/{target_id}/receivers", tags=["target-receivers"])


class ReceiverCreate(BaseModel):
    name: str = ""
    config: dict[str, Any] = {}
    locale: str = ""
    enabled: bool = True


class ReceiverUpdate(BaseModel):
    name: str | None = None
    config: dict[str, Any] | None = None
    locale: str | None = None
    enabled: bool | None = None


def _receiver_key(target_type: str, config: dict[str, Any]) -> str:
    """Derive a unique key for deduplication from receiver config."""
    key_fields = {
        "telegram": "chat_id",
        "webhook": "url",
        "email": "email",
        "discord": "webhook_url",
        "slack": "webhook_url",
        "ntfy": "topic",
        "matrix": "room_id",
    }
    field = key_fields.get(target_type, "")
    return str(config.get(field, "")) if field else ""


@router.get("")
async def list_receivers(
    target_id: int,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    target = await _get_user_target(session, target_id, user.id)
    result = await session.exec(
        select(TargetReceiver).where(TargetReceiver.target_id == target.id)
    )
    return [_response(r) for r in result.all()]


@router.post("", status_code=status.HTTP_201_CREATED)
async def create_receiver(
    target_id: int,
    body: ReceiverCreate,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    target = await _get_user_target(session, target_id, user.id)
    key = _receiver_key(target.type, body.config)
    if not key:
        raise HTTPException(status_code=400, detail="Receiver config must include a delivery endpoint (chat_id, url, or email)")

    # Check for duplicate
    existing = await session.exec(
        select(TargetReceiver).where(
            TargetReceiver.target_id == target.id,
            TargetReceiver.receiver_key == key,
        )
    )
    if existing.first():
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Receiver already exists for this target")

    receiver = TargetReceiver(
        target_id=target.id,
        name=body.name,
        config=body.config,
        receiver_key=key,
        locale=body.locale,
        enabled=body.enabled,
    )
    session.add(receiver)
    await session.commit()
    await session.refresh(receiver)
    return _response(receiver)


@router.put("/{receiver_id}")
async def update_receiver(
    target_id: int,
    receiver_id: int,
    body: ReceiverUpdate,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    await _get_user_target(session, target_id, user.id)
    receiver = await session.get(TargetReceiver, receiver_id)
    if not receiver or receiver.target_id != target_id:
        raise HTTPException(status_code=404, detail="Receiver not found")

    for field, value in body.model_dump(exclude_unset=True).items():
        setattr(receiver, field, value)
    # Update receiver_key if config changed
    if body.config is not None:
        target = await session.get(NotificationTarget, target_id)
        receiver.receiver_key = _receiver_key(target.type, receiver.config)
    session.add(receiver)
    await session.commit()
    await session.refresh(receiver)
    return _response(receiver)


@router.post("/{receiver_id}/test")
async def test_receiver(
    target_id: int,
    receiver_id: int,
    locale: str = Query("en"),
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    """Send a test notification to a single receiver.

    For Telegram targets, locale resolution goes through the shared
    ``resolve_telegram_chat_locale`` helper so the per-chat ``language_override``
    set in the bot manager is respected here too — previously this endpoint
    only consulted ``receiver.locale`` and ignored chat-side overrides.
    """
    target = await _get_user_target(session, target_id, user.id)
    receiver = await session.get(TargetReceiver, receiver_id)
    if not receiver or receiver.target_id != target_id:
        raise HTTPException(status_code=404, detail="Receiver not found")

    if target.type == "telegram":
        effective_locale = await resolve_telegram_chat_locale(
            session,
            bot_id=target.config.get("bot_id"),
            chat_id=receiver.config.get("chat_id"),
            receiver=receiver,
            fallback=locale,
        )
    else:
        effective_locale = (getattr(receiver, "locale", "") or locale)[:2].lower()
    message = _get_test_message(effective_locale, target.type)
    return await send_to_receiver(target, dict(receiver.config), message)


@router.delete("/{receiver_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_receiver(
    target_id: int,
    receiver_id: int,
    user: User = Depends(get_current_user),
    session: AsyncSession = Depends(get_session),
):
    await _get_user_target(session, target_id, user.id)
    receiver = await session.get(TargetReceiver, receiver_id)
    if not receiver or receiver.target_id != target_id:
        raise HTTPException(status_code=404, detail="Receiver not found")
    await session.delete(receiver)
    await session.commit()


def _response(r: TargetReceiver) -> dict:
    return {
        "id": r.id,
        "target_id": r.target_id,
        "name": r.name,
        "config": dict(r.config),
        "receiver_key": r.receiver_key,
        "locale": getattr(r, 'locale', '') or '',
        "enabled": r.enabled,
        "created_at": r.created_at.isoformat(),
    }


async def _get_user_target(session: AsyncSession, target_id: int, user_id: int) -> NotificationTarget:
    return await get_owned_entity(
        session, NotificationTarget, target_id, user_id,
        not_found_msg="Target not found",
    )
