"""/api/clients + /api/contacts — the PlusROI Clients & Contacts write
forms (phase-3 slice 1). Thin HTTP layer: every rule (owner gate,
sheet-owned write-block, tenant scope, dedup, validation, audit) lives in
``services/clients.py``; this file only shapes requests and translates
``ServiceError`` -> the structured ApiError triple."""

from __future__ import annotations

import uuid

from fastapi import APIRouter
from pydantic import BaseModel

from app.routers.deps import ActorDep, ApiError, SessionDep
from app.services import clients as clients_svc
from app.services.errors import ServiceError

router = APIRouter()


def _run(fn, *args, **kwargs):
    try:
        return fn(*args, **kwargs)
    except ServiceError as exc:
        raise ApiError(exc.status, exc.code, exc.summary, exc.detail) from exc


class ContactInput(BaseModel):
    name: str = ""
    email: str | None = None


class ClientCreate(BaseModel):
    name: str = ""
    official_name: str | None = None
    address: str | None = None
    phone: str | None = None
    currency: str | None = None
    terms: str | None = None
    invoice_timing: str | None = None
    credit_limit: str | None = None
    default_commission_pct: str | None = None
    commission_party_id: str | None = None
    archived: bool = False
    contacts: list[ContactInput] = []


class ClientPatch(BaseModel):
    """PATCH semantics: only the SET fields reach the service (an omitted
    field is never touched; a provided blank clears it per the service)."""

    name: str | None = None
    official_name: str | None = None
    address: str | None = None
    phone: str | None = None
    currency: str | None = None
    terms: str | None = None
    invoice_timing: str | None = None
    credit_limit: str | None = None
    default_commission_pct: str | None = None
    commission_party_id: str | None = None
    archived: bool | None = None


class ContactCreate(BaseModel):
    name: str = ""
    email: str = ""


@router.get("/api/clients")
def list_clients(session: SessionDep, actor: ActorDep) -> dict:
    return _run(clients_svc.list_clients, session, actor)


@router.post("/api/clients")
def create_client(session: SessionDep, actor: ActorDep, body: ClientCreate) -> dict:
    payload = body.model_dump()
    return _run(clients_svc.create_client, session, actor, payload)


@router.get("/api/clients/{party_id}")
def get_client(session: SessionDep, actor: ActorDep, party_id: uuid.UUID) -> dict:
    return _run(clients_svc.get_client, session, actor, party_id)


@router.patch("/api/clients/{party_id}")
def update_client(
    session: SessionDep, actor: ActorDep, party_id: uuid.UUID, body: ClientPatch
) -> dict:
    patch = {k: getattr(body, k) for k in body.model_fields_set}
    return _run(clients_svc.update_client, session, actor, party_id, patch)


@router.post("/api/clients/{party_id}/contacts")
def add_contact(
    session: SessionDep, actor: ActorDep, party_id: uuid.UUID, body: ContactCreate
) -> dict:
    return _run(clients_svc.add_contact, session, actor, party_id, body.model_dump())


@router.get("/api/contacts")
def list_contacts(session: SessionDep, actor: ActorDep) -> dict:
    return _run(clients_svc.list_contacts, session, actor)


@router.delete("/api/contacts/{affiliation_id}")
def remove_contact(
    session: SessionDep, actor: ActorDep, affiliation_id: uuid.UUID
) -> dict:
    return _run(clients_svc.remove_contact, session, actor, affiliation_id)
