"""Authorization helpers for ledger mutation endpoints."""

from __future__ import annotations

from fastapi import HTTPException

from app.services import users as user_service
from app.services.notifications import resolve_client_id
from app.store import Invoice, store


def require_firm(*, platform: str, email: str, actor: str | None = None) -> str:
    """Firm-only actions. Returns the display name to use in audit logs."""
    platform_n = (platform or "").strip().lower()
    email_n = (email or "").strip().lower()
    if platform_n != "firm":
        raise HTTPException(status_code=403, detail="Only firm users can perform this action")
    if not email_n or "@" not in email_n:
        raise HTTPException(status_code=401, detail="Authentication required")

    user = user_service.get_user("firm", email_n)
    if not user:
        # Demo / first-login firm accounts may exist only in session until provisioned.
        # Require a firm user row for mutations.
        raise HTTPException(status_code=403, detail="Firm account not found")

    name = (actor or "").strip() or (user.name or "").strip() or email_n
    return name


def require_authenticated(*, platform: str, email: str) -> tuple[str, str]:
    platform_n = (platform or "").strip().lower()
    email_n = (email or "").strip().lower()
    if platform_n not in {"firm", "client"}:
        raise HTTPException(status_code=400, detail="Invalid platform")
    if not email_n or "@" not in email_n:
        raise HTTPException(status_code=401, detail="Authentication required")
    user = user_service.get_user(platform_n, email_n)
    if not user:
        raise HTTPException(status_code=403, detail="Account not found")
    return platform_n, email_n


def require_invoice_access(*, platform: str, email: str, invoice: Invoice) -> None:
    """Firm may access any invoice; clients only their own."""
    platform_n = (platform or "").strip().lower()
    email_n = (email or "").strip().lower()
    if platform_n == "firm":
        require_firm(platform=platform_n, email=email_n)
        return
    if platform_n == "client":
        client_id = resolve_client_id(platform_n, email_n)
        if not client_id or invoice.clientId != client_id:
            raise HTTPException(status_code=403, detail="You do not have access to this document")
        return
    raise HTTPException(status_code=400, detail="Invalid platform")


def require_firm_invoice(*, platform: str, email: str, invoice_id: str, actor: str | None = None) -> tuple[Invoice, str]:
    actor_name = require_firm(platform=platform, email=email, actor=actor)
    try:
        invoice = store._find_invoice(invoice_id)  # noqa: SLF001
    except KeyError as exc:
        raise HTTPException(status_code=404, detail="Document not found") from exc
    return invoice, actor_name
