"""/api/import — the Clockify import pipeline (M4): upload -> staged
pending -> resolution payload -> commit / cancel, plus batch list +
delete-with-guard. Thin HTTP layer: every rule lives in
services/imports (04-architecture)."""

from __future__ import annotations

import uuid
from typing import Annotated

from fastapi import APIRouter, File, Form, UploadFile
from pydantic import BaseModel, Field

from app.routers.deps import ActorDep, ApiError, SessionDep
from app.services.imports import batches as batches_svc
from app.services.imports import commit as commit_svc
from app.services.imports import resolver as resolver_svc
from app.services.imports import staging as staging_svc
from app.services.imports.errors import ImportsError
from app.services.imports.staging import MAX_UPLOAD_BYTES

router = APIRouter()


def _run(fn, *args, **kwargs):
    """Translate the service-layer ImportsError into the app-wide
    structured HTTP error triple."""
    try:
        return fn(*args, **kwargs)
    except ImportsError as exc:
        raise ApiError(exc.status, exc.code, exc.summary, exc.detail) from exc


class EntityDecision(BaseModel):
    name: str
    operator: str | None = None  # clients + projects
    client: str | None = None  # projects
    decision: str = "create"  # create | map
    target_id: str | None = None


class BucketDecision(BaseModel):
    operator: str | None = None
    client: str | None = None
    project: str | None = None
    decision: str = "create"  # map | create | skip
    target_project_id: str | None = None
    create_operator: str | None = None
    create_client: str | None = None
    create_project: str | None = None


class CommitDecisions(BaseModel):
    operators: list[EntityDecision] = Field(default_factory=list)
    clients: list[EntityDecision] = Field(default_factory=list)
    projects: list[EntityDecision] = Field(default_factory=list)
    buckets: list[BucketDecision] = Field(default_factory=list)


@router.post("/api/import")
def upload_csv(
    session: SessionDep,
    actor: ActorDep,
    file: Annotated[UploadFile | None, File()] = None,
    name: Annotated[str | None, Form()] = None,
    notes: Annotated[str | None, Form()] = None,
) -> dict:
    """Multipart CSV upload -> staged pending import; responds with the
    full resolution payload so the SPA can route straight to the
    resolver (T-IMP-012)."""
    data = b""
    filename = None
    if file is not None:
        # read one byte past the cap so the size guard can fire without
        # buffering an arbitrarily large body
        data = file.file.read(MAX_UPLOAD_BYTES + 1)
        filename = file.filename
    pending = _run(
        staging_svc.stage_upload,
        session,
        actor,
        filename=filename,
        data=data,
        batch_name=name,
        notes=notes,
    )
    payload = _run(resolver_svc.resolution_payload, session, actor, pending)
    payload["pending_id"] = str(pending.id)
    return payload


@router.get("/api/import/pending/{pending_id}")
def get_pending(session: SessionDep, actor: ActorDep, pending_id: uuid.UUID) -> dict:
    pending = _run(staging_svc.get_pending, session, actor, pending_id)
    payload = _run(resolver_svc.resolution_payload, session, actor, pending)
    payload["pending_id"] = str(pending.id)
    return payload


@router.post("/api/import/pending/{pending_id}/commit")
def commit_pending(
    session: SessionDep,
    actor: ActorDep,
    pending_id: uuid.UUID,
    decisions: CommitDecisions,
) -> dict:
    return _run(
        commit_svc.commit_pending,
        session,
        actor,
        pending_id,
        decisions.model_dump(),
    )


@router.delete("/api/import/pending/{pending_id}")
def cancel_pending(session: SessionDep, actor: ActorDep, pending_id: uuid.UUID) -> dict:
    _run(staging_svc.cancel_pending, session, actor, pending_id)
    return {"ok": True}


@router.get("/api/import/batches")
def list_batches(session: SessionDep, actor: ActorDep) -> dict:
    """Batch metadata is tenant-visible to any role (B74); the upload
    panel/deletability ride on can_manage_imports."""
    return {
        "rows": batches_svc.list_batches(session, actor),
        "can_manage": actor.allowed("can_manage_imports"),
    }


@router.get("/api/import/batches/{batch_id}/summary")
def batch_summary(session: SessionDep, actor: ActorDep, batch_id: uuid.UUID) -> dict:
    return _run(batches_svc.batch_summary, session, actor, batch_id)


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