from __future__ import annotations

from fastapi import APIRouter, HTTPException, Query
from pydantic import EmailStr

from app.services.ledger_auth import require_authenticated, require_firm
from app.services.notifications import resolve_client_id
from app.store import (
    AnswerQueryRequest,
    CancelQueryRequest,
    CreateQueryRequest,
    QueryActorRequest,
    QueryMessageRequest,
    store,
)

router = APIRouter(prefix="/v1/queries", tags=["queries"])


def _require_query_access(
    query_id: str,
    *,
    platform: str,
    email: str,
) -> tuple[str, str | None]:
    """Return (platform, client_id) after verifying access to the query."""
    require_authenticated(platform=platform, email=email)
    client_id = resolve_client_id(platform, email)
    try:
        query = store._find_query(query_id)  # noqa: SLF001
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Query not found") from exc
    if platform == "client":
        if not client_id or query.clientId != client_id:
            raise HTTPException(status_code=403, detail="You do not have access to this question")
    return platform, client_id


@router.get("")
def list_queries(
    platform: str = Query(pattern="^(firm|client)$"),
    email: EmailStr = Query(...),
    clientId: str | None = None,
    status: str | None = None,
    priority: str | None = None,
    dateFrom: str | None = None,
    dateTo: str | None = None,
    invoiceId: str | None = None,
    q: str | None = None,
):
    require_authenticated(platform=platform, email=str(email))
    resolved_client = resolve_client_id(platform, str(email))
    if platform == "client":
        if not resolved_client:
            return {"items": [], "stats": store.query_stats(client_id=None)}
        client_filter = resolved_client
    else:
        client_filter = clientId

    items = store.list_queries(
        client_id=client_filter,
        status=status,
        priority=priority,
        date_from=dateFrom,
        date_to=dateTo,
        query=q,
        invoice_id=invoiceId,
    )
    stats = store.query_stats(client_id=client_filter if platform == "client" else clientId)
    return {"items": items, "stats": stats}


@router.get("/{query_id}")
def get_query(
    query_id: str,
    platform: str = Query(pattern="^(firm|client)$"),
    email: EmailStr = Query(...),
):
    _require_query_access(query_id, platform=platform, email=str(email))
    return store._find_query(query_id)  # noqa: SLF001


@router.post("")
def create_query(payload: CreateQueryRequest):
    actor = require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    if not payload.question.strip():
        raise HTTPException(status_code=400, detail="Please enter a question")
    if not any(c.id == payload.clientId for c in store.snapshot().clients):
        raise HTTPException(status_code=404, detail="Client not found")
    if payload.invoiceId:
        try:
            inv = store._find_invoice(payload.invoiceId)  # noqa: SLF001
        except KeyError as exc:
            raise HTTPException(status_code=404, detail="Document not found") from exc
        if inv.clientId != payload.clientId:
            raise HTTPException(status_code=400, detail="Document does not belong to this client")
    try:
        return store.create_query(payload, actor=actor)
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.get("/{query_id}/messages")
def get_query_messages(
    query_id: str,
    platform: str = Query(pattern="^(firm|client)$"),
    email: EmailStr = Query(...),
):
    _require_query_access(query_id, platform=platform, email=str(email))
    query = store._find_query(query_id)  # noqa: SLF001
    return {"items": query.messages}


@router.post("/{query_id}/messages")
def add_query_message(query_id: str, payload: QueryMessageRequest):
    platform, email = require_authenticated(platform=payload.platform, email=payload.email)
    if not payload.message.strip():
        raise HTTPException(status_code=400, detail="Message cannot be empty")

    _require_query_access(query_id, platform=platform, email=email)

    if platform == "client":
        client_id = resolve_client_id(platform, email)
        client = store.get_client(client_id) if client_id else None
        sender_name = client.name if client else "Client"
        try:
            return store.add_query_message(
                query_id,
                sender_role="client",
                sender_name=sender_name,
                message=payload.message,
                attachment_ref=payload.attachmentRef,
            )
        except ValueError as exc:
            raise HTTPException(status_code=400, detail=str(exc)) from exc

    actor = require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    try:
        return store.add_query_message(
            query_id,
            sender_role="firm",
            sender_name=actor,
            message=payload.message,
            attachment_ref=payload.attachmentRef,
        )
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.post("/{query_id}/answer")
def answer_query(query_id: str, payload: AnswerQueryRequest):
    platform, email = require_authenticated(platform=payload.platform, email=payload.email)
    if platform != "client":
        raise HTTPException(status_code=403, detail="Only clients can answer questions")
    _require_query_access(query_id, platform=platform, email=email)
    if not payload.answer.strip():
        raise HTTPException(status_code=400, detail="Please enter an answer")
    try:
        return store.answer_query(query_id, payload)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Query not found") from exc
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.post("/{query_id}/resolve")
def resolve_query(query_id: str, payload: QueryActorRequest):
    actor = require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    try:
        store._find_query(query_id)  # noqa: SLF001
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Query not found") from exc
    try:
        return store.resolve_query(query_id, actor=actor)
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.post("/{query_id}/cancel")
def cancel_query(query_id: str, payload: CancelQueryRequest):
    actor = require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    try:
        store._find_query(query_id)  # noqa: SLF001
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Query not found") from exc
    try:
        return store.cancel_query(query_id, actor=actor, reason=payload.reason)
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc


@router.post("/{query_id}/approve")
def approve_query_legacy(query_id: str, payload: QueryActorRequest):
    """Legacy endpoint — resolves the query."""
    actor = require_firm(platform=payload.platform, email=payload.email, actor=payload.actor)
    try:
        return store.resolve_query(query_id, actor=actor)
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Query not found") from exc
    except ValueError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc
