"""/api/cc — CC pass-through expenses (cc-expenses.md). Thin HTTP layer:
every rule lives in services/cc/service.py (04-architecture). Owner-only
across the board — the service raises NOT_ALLOWED ("Owner only." /
"Only an owner can …") for non-owners, translated to the structured
error triple here."""

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.cc import service as cc_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


# --------------------------------------------------------------- bodies


class BatchCreate(BaseModel):
    name: str = ""


class PasteBody(BaseModel):
    paste: str = ""


class LinePatch(BaseModel):
    """Per-row Save (B28): project (existing id or null = unassign) +
    free-text description/category. Every save flips auto_assigned false."""

    project_id: str | None = None
    assignment_description: str | None = None
    category: str | None = None


class KeywordCreate(BaseModel):
    keyword: str = ""


class RuleBody(BaseModel):
    keyword: str = ""
    project_id: str | None = None
    assignment_description: str | None = None
    category: str | None = None


# ------------------------------------------------------------- batches


@router.get("/api/cc/batches")
def list_batches(session: SessionDep, actor: ActorDep) -> dict:
    return {"rows": _run(cc_svc.list_batches, session, actor)}


@router.post("/api/cc/batches")
def create_batch(session: SessionDep, actor: ActorDep, body: BatchCreate) -> dict:
    return {"ok": True, "row": _run(cc_svc.create_batch, session, actor, body.name)}


@router.get("/api/cc/batches/{batch_id}")
def batch_detail(session: SessionDep, actor: ActorDep, batch_id: uuid.UUID) -> dict:
    return _run(cc_svc.batch_detail, session, actor, batch_id)


@router.delete("/api/cc/batches/{batch_id}")
def delete_batch(session: SessionDep, actor: ActorDep, batch_id: uuid.UUID) -> dict:
    return _run(cc_svc.delete_batch, session, actor, batch_id)


@router.post("/api/cc/batches/{batch_id}/lines")
def append_lines(
    session: SessionDep, actor: ActorDep, batch_id: uuid.UUID, body: PasteBody
) -> dict:
    return _run(cc_svc.append_lines, session, actor, batch_id, body.paste)


@router.post("/api/cc/batches/{batch_id}/reapply")
def reapply_rules(session: SessionDep, actor: ActorDep, batch_id: uuid.UUID) -> dict:
    return _run(cc_svc.reapply_rules, session, actor, batch_id)


@router.get("/api/cc/batches/{batch_id}/paste-block")
def paste_block(session: SessionDep, actor: ActorDep, batch_id: uuid.UUID) -> dict:
    return _run(cc_svc.paste_block, session, actor, batch_id)


class PortBody(BaseModel):
    """Port assigned lines into PlusROI expenses (phase-3 slice 3).
    ``line_ids`` narrows to a selection (omitted = the whole batch);
    ``paid_by_party_id`` overrides the default (the caller's own party)."""

    line_ids: list[str] | None = None
    paid_by_party_id: str | None = None


@router.post("/api/cc/batches/{batch_id}/port-to-expenses")
def port_to_expenses(
    session: SessionDep, actor: ActorDep, batch_id: uuid.UUID, body: PortBody
) -> dict:
    return _run(cc_svc.port_to_expenses, session, actor, batch_id, body.model_dump())


# --------------------------------------------------------------- lines


@router.patch("/api/cc/lines/{line_id}")
def update_line(
    session: SessionDep, actor: ActorDep, line_id: uuid.UUID, body: LinePatch
) -> dict:
    return _run(cc_svc.update_line, session, actor, line_id, body.model_dump())


@router.delete("/api/cc/lines/{line_id}")
def delete_line(session: SessionDep, actor: ActorDep, line_id: uuid.UUID) -> dict:
    return _run(cc_svc.delete_line, session, actor, line_id)


# --------------------------------------------------------- rules & keywords


@router.get("/api/cc/rules")
def rules_payload(session: SessionDep, actor: ActorDep) -> dict:
    return _run(cc_svc.rules_payload, session, actor)


@router.post("/api/cc/keywords")
def create_keyword(session: SessionDep, actor: ActorDep, body: KeywordCreate) -> dict:
    return _run(cc_svc.create_highlight_keyword, session, actor, body.keyword)


@router.delete("/api/cc/keywords/{keyword_id}")
def delete_keyword(session: SessionDep, actor: ActorDep, keyword_id: uuid.UUID) -> dict:
    return _run(cc_svc.delete_highlight_keyword, session, actor, keyword_id)


@router.post("/api/cc/rules")
def create_rule(session: SessionDep, actor: ActorDep, body: RuleBody) -> dict:
    return _run(cc_svc.create_auto_rule, session, actor, body.model_dump())


@router.patch("/api/cc/rules/{rule_id}")
def update_rule(
    session: SessionDep, actor: ActorDep, rule_id: uuid.UUID, body: RuleBody
) -> dict:
    return _run(cc_svc.update_auto_rule, session, actor, rule_id, body.model_dump())


@router.delete("/api/cc/rules/{rule_id}")
def delete_rule(session: SessionDep, actor: ActorDep, rule_id: uuid.UUID) -> dict:
    return _run(cc_svc.delete_auto_rule, session, actor, rule_id)
