"""Docling API routes for doc-ingest service."""
from __future__ import annotations

import os
from pathlib import Path
from typing import Any, Optional

from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel, Field

from app.docling_service import capabilities, convert_nas_batch, convert_nas_file, get_result, list_history

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

NAS_ROOT = Path(os.getenv("NAS_ROOT", "/nas"))


class DoclingConvertBody(BaseModel):
    path: str = Field(..., min_length=1, description="Relatief NAS-pad")
    ocr: bool = True
    tables: bool = True
    page_images: bool = False
    picture_images: bool = True
    force_full_page_ocr: bool = False
    formats: list[str] = Field(default_factory=lambda: ["markdown", "html", "json", "text"])


class DoclingBatchBody(BaseModel):
    paths: list[str] = Field(default_factory=list)
    limit: int = Field(default=10, ge=1, le=50)
    ext: Optional[str] = None
    ocr: bool = True
    tables: bool = True
    page_images: bool = False
    picture_images: bool = True
    force_full_page_ocr: bool = False
    formats: list[str] = Field(default_factory=lambda: ["markdown", "json"])


def _options(body: DoclingConvertBody | DoclingBatchBody) -> dict[str, Any]:
    return {
        "ocr": body.ocr,
        "tables": body.tables,
        "page_images": body.page_images,
        "picture_images": body.picture_images,
        "force_full_page_ocr": body.force_full_page_ocr,
        "formats": body.formats,
    }


@router.get("/capabilities")
def docling_capabilities() -> dict[str, Any]:
    return {"ok": True, **capabilities()}


@router.post("/convert")
def docling_convert(body: DoclingConvertBody) -> dict[str, Any]:
    if not NAS_ROOT.is_dir():
        raise HTTPException(503, f"NAS not mounted at {NAS_ROOT}")
    caps = capabilities()
    if not caps.get("installed"):
        raise HTTPException(503, "Docling not installed on doc-ingest service")
    out = convert_nas_file(NAS_ROOT, body.path.lstrip("/"), _options(body))
    if not out.get("ok"):
        raise HTTPException(502, out.get("error") or "Conversion failed")
    return out


@router.post("/batch")
def docling_batch(body: DoclingBatchBody) -> dict[str, Any]:
    if not NAS_ROOT.is_dir():
        raise HTTPException(503, f"NAS not mounted at {NAS_ROOT}")
    caps = capabilities()
    if not caps.get("installed"):
        raise HTTPException(503, "Docling not installed on doc-ingest service")
    paths = list(body.paths or [])
    if not paths:
        from app.ingest import scan_share_files

        files = scan_share_files(NAS_ROOT)
        if body.ext:
            want = body.ext if body.ext.startswith(".") else f".{body.ext}"
            files = [f for f in files if f.suffix.lower() == want.lower()]
        paths = [str(f.relative_to(NAS_ROOT)) for f in files[: body.limit]]
    if not paths:
        return {"ok": True, "converted": 0, "total": 0, "results": []}
    return convert_nas_batch(NAS_ROOT, paths, _options(body))


@router.get("/history")
def docling_history(limit: int = Query(default=30, ge=1, le=100)) -> dict[str, Any]:
    return {"ok": True, "items": list_history(limit)}


@router.get("/result")
def docling_result(
    path: str = Query(..., min_length=1),
    file_sig: Optional[str] = None,
) -> dict[str, Any]:
    row = get_result(path.lstrip("/"), file_sig)
    if not row:
        raise HTTPException(404, "No Docling result for this file")
    return {"ok": True, "result": row}


class NasWriteBody(BaseModel):
    path: str = Field(..., min_length=1, description="Bronbestand (voor bestandsnaam)")
    content: str = ""
    subdir: str = Field(default="Telegram/Exports", max_length=256)


@router.get("/nas/diagnostics")
def docling_nas_diagnostics() -> dict[str, Any]:
    if not NAS_ROOT.is_dir():
        return {"ok": False, "nas_mounted": False, "error": f"NAS not at {NAS_ROOT}"}
    from app.ingest import scan_share_files, SKIP_DIR_NAMES

    all_files = scan_share_files(NAS_ROOT)
    folder_counts: dict[str, int] = {}
    for p in all_files:
        top = p.relative_to(NAS_ROOT).parts[0] if p.relative_to(NAS_ROOT).parts else "."
        folder_counts[top] = folder_counts.get(top, 0) + 1
    empty_tops = []
    for child in NAS_ROOT.iterdir():
        if not child.is_dir() or child.name.startswith(("#", ".")) or child.name in SKIP_DIR_NAMES:
            continue
        if child.name not in folder_counts:
            empty_tops.append(child.name)
    return {
        "ok": True,
        "nas_mounted": True,
        "total_files": len(all_files),
        "by_top_folder": folder_counts,
        "empty_folder_trees": empty_tops,
        "hint": (
            "Mappen zonder zichtbare bestanden = Synology ACL probleem. "
            "Geef SMB-gebruiker aissa Read/Write op share + submappen in DSM."
        ) if empty_tops else "",
    }


TEXT_SUFFIXES = {
    ".txt", ".md", ".csv", ".json", ".xml", ".html", ".htm", ".yaml", ".yml", ".log", ".rtf",
}
IMAGE_SUFFIXES = {".png", ".jpg", ".jpeg", ".webp", ".gif", ".bmp", ".tiff", ".tif"}
PREVIEW_SUFFIXES = TEXT_SUFFIXES | IMAGE_SUFFIXES | {".pdf"}


@router.get("/nas/read")
def docling_nas_read(path: str = Query(..., min_length=1)) -> dict[str, Any]:
    if not NAS_ROOT.is_dir():
        raise HTTPException(503, f"NAS not mounted at {NAS_ROOT}")
    rel = path.lstrip("/")
    full = (NAS_ROOT / rel).resolve()
    if not str(full).startswith(str(NAS_ROOT.resolve())) or not full.is_file():
        raise HTTPException(404, "File not found")
    ext = full.suffix.lower()
    if ext not in TEXT_SUFFIXES and ext not in {".csv", ".rtf"}:
        raise HTTPException(400, f"Not a plain-text file: {ext}")
    try:
        content = full.read_text(encoding="utf-8")
    except UnicodeDecodeError:
        content = full.read_text(encoding="latin-1", errors="replace")
    return {
        "ok": True,
        "path": rel,
        "filename": full.name,
        "extension": ext,
        "content": content,
        "bytes": full.stat().st_size,
        "editable": True,
    }


@router.get("/nas/file")
def docling_nas_file(path: str = Query(..., min_length=1)):
    from fastapi.responses import FileResponse

    if not NAS_ROOT.is_dir():
        raise HTTPException(503, f"NAS not mounted at {NAS_ROOT}")
    rel = path.lstrip("/")
    full = (NAS_ROOT / rel).resolve()
    if not str(full).startswith(str(NAS_ROOT.resolve())) or not full.is_file():
        raise HTTPException(404, "File not found")
    media = "application/octet-stream"
    ext = full.suffix.lower()
    if ext == ".pdf":
        media = "application/pdf"
    elif ext in IMAGE_SUFFIXES:
        media = f"image/{ext.lstrip('.')}"
        if ext == ".jpg":
            media = "image/jpeg"
    elif ext == ".html":
        media = "text/html"
    return FileResponse(full, media_type=media, filename=full.name)


@router.post("/nas/write")
def docling_nas_write(body: NasWriteBody) -> dict[str, Any]:
    if not NAS_ROOT.is_dir():
        raise HTTPException(503, f"NAS not mounted at {NAS_ROOT}")
    subdir = body.subdir.strip().strip("/")
    out_dir = (NAS_ROOT / subdir).resolve()
    if not str(out_dir).startswith(str(NAS_ROOT.resolve())):
        raise HTTPException(400, "Invalid subdir")
    out_dir.mkdir(parents=True, exist_ok=True)
    stem = Path(body.path.lstrip("/")).stem
    fname = f"{stem}-edited.md"
    full = out_dir / fname
    full.write_text(body.content or "", encoding="utf-8")
    rel = str(full.relative_to(NAS_ROOT))
    return {"ok": True, "path": rel, "filename": fname, "bytes": len(body.content or "")}
