from __future__ import annotations

from pathlib import Path
from typing import Any, Optional

import httpx
from fastapi import APIRouter, HTTPException, Query, Request
from fastapi.responses import Response
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel, Field

from app.config import settings
from app.services import packaging_nas, projects

router = APIRouter(tags=["packaging"])
BASE_DIR = Path(__file__).resolve().parent.parent.parent
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
TOOLS = settings.TOOLS_API_URL.rstrip("/")


class PackagingGenerateBody(BaseModel):
    type: str = Field(default="folding_box")
    width_mm: float = Field(default=120, gt=0)
    height_mm: float = Field(default=80, gt=0)
    depth_mm: float = Field(default=40, ge=0)
    bleed_mm: float = Field(default=3, ge=0)
    elements: dict[str, bool] = Field(default_factory=dict)
    brand: dict[str, str] = Field(default_factory=dict)
    text: dict[str, Any] = Field(default_factory=dict)
    barcode_value: str | None = None
    qr_value: str | None = None
    design_name: str | None = None
    project_id: int | None = None
    project_name: str | None = None
    client_id: int | None = None
    created_by: str = "ceo"


class PackagingEmailBody(BaseModel):
    to: list[str] = Field(..., min_length=1)
    subject: str = Field(..., min_length=1)
    body: str = ""
    cc: list[str] = Field(default_factory=list)
    client_id: int | None = None


class CopyToProjectBody(BaseModel):
    target_project_id: int


async def _tools_request(method: str, path: str, **kwargs) -> httpx.Response:
    async with httpx.AsyncClient(timeout=120.0) as client:
        r = await client.request(method, f"{TOOLS}{path}", **kwargs)
        return r


def _tools_error(exc: httpx.HTTPStatusError) -> HTTPException:
    detail = exc.response.text[:500] if exc.response else str(exc)
    return HTTPException(status_code=exc.response.status_code if exc.response else 502, detail=detail)


async def _ensure_project(body: PackagingGenerateBody) -> PackagingGenerateBody:
    if body.project_id or not body.project_name:
        return body
    proj = projects.create_project(
        body.project_name.strip(),
        client_id=body.client_id,
        description="Packaging design project",
        project_type="packaging",
        ensure_nas=True,
    )
    data = body.model_dump()
    data["project_id"] = proj.get("id")
    return PackagingGenerateBody(**data)


async def _post_nas_export(result: dict[str, Any]) -> dict[str, Any]:
    pid = result.get("cockpit_project_id")
    packaging_id = result.get("id")
    svg = result.get("svg") or ""
    spec = result.get("spec") or {}
    if not pid or not packaging_id or not svg:
        return result
    png_bytes = pdf_bytes = None
    try:
        png_r = await _tools_request("GET", f"/packaging/download/{packaging_id}", params={"format": "png"})
        if png_r.status_code < 400:
            png_bytes = png_r.content
        pdf_r = await _tools_request("GET", f"/packaging/download/{packaging_id}", params={"format": "pdf"})
        if pdf_r.status_code < 400:
            pdf_bytes = pdf_r.content
    except Exception:
        pass
    try:
        nas_info = packaging_nas.export_packaging_files(packaging_id, int(pid), svg, spec, png_bytes, pdf_bytes)
        result["nas"] = nas_info
    except Exception as exc:
        result["nas"] = {"ok": False, "error": str(exc)}
    return result


@router.get("/packaging")
async def packaging_page(request: Request, project_id: Optional[int] = None):
    return templates.TemplateResponse(
        "packaging.html",
        {"request": request, "page_title": "Packaging Studio", "initial_project_id": project_id},
    )


@router.get("/api/packaging/types")
async def proxy_packaging_types():
    try:
        r = await _tools_request("GET", "/packaging/types")
        r.raise_for_status()
        return r.json()
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.post("/api/packaging/preview")
async def proxy_packaging_preview(body: PackagingGenerateBody):
    try:
        r = await _tools_request("POST", "/packaging/preview", json=body.model_dump())
        r.raise_for_status()
        return r.json()
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.post("/api/packaging/generate")
async def proxy_packaging_generate(body: PackagingGenerateBody):
    try:
        body = await _ensure_project(body)
        r = await _tools_request("POST", "/packaging/generate", json=body.model_dump())
        r.raise_for_status()
        result = r.json()
        return await _post_nas_export(result)
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.get("/api/packaging/projects")
async def proxy_packaging_projects(limit: int = 30):
    try:
        r = await _tools_request("GET", "/packaging/projects", params={"limit": limit})
        r.raise_for_status()
        return r.json()
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.get("/api/packaging/download/{project_id}")
async def proxy_packaging_download(project_id: str, format: str = "svg"):
    try:
        r = await _tools_request("GET", f"/packaging/download/{project_id}", params={"format": format})
        r.raise_for_status()
        media = r.headers.get("content-type", "application/octet-stream")
        disposition = r.headers.get("content-disposition")
        headers = {"content-disposition": disposition} if disposition else {}
        return Response(content=r.content, media_type=media, headers=headers)
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.get("/api/packaging/{packaging_id}")
async def proxy_packaging_get(packaging_id: str):
    try:
        r = await _tools_request("GET", f"/packaging/{packaging_id}")
        r.raise_for_status()
        return r.json()
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.patch("/api/packaging/{packaging_id}")
async def proxy_packaging_update(packaging_id: str, body: PackagingGenerateBody):
    try:
        r = await _tools_request("PATCH", f"/packaging/{packaging_id}", json={"spec": body.model_dump()})
        r.raise_for_status()
        result = r.json()
        return await _post_nas_export(result)
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.post("/api/packaging/{packaging_id}/duplicate")
async def proxy_packaging_duplicate(packaging_id: str):
    try:
        r = await _tools_request("POST", f"/packaging/{packaging_id}/duplicate")
        r.raise_for_status()
        result = r.json()
        return await _post_nas_export(result)
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.post("/api/packaging/{packaging_id}/copy-to-project")
async def proxy_packaging_copy(packaging_id: str, body: CopyToProjectBody):
    try:
        r = await _tools_request(
            "POST",
            f"/packaging/{packaging_id}/copy-to-project",
            json=body.model_dump(),
        )
        r.raise_for_status()
        result = r.json()
        return await _post_nas_export(result)
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.delete("/api/packaging/{packaging_id}")
async def proxy_packaging_delete(packaging_id: str):
    try:
        r = await _tools_request("DELETE", f"/packaging/{packaging_id}")
        r.raise_for_status()
        return r.json()
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc


@router.post("/api/packaging/{packaging_id}/email")
async def proxy_packaging_email(packaging_id: str, body: PackagingEmailBody):
    base = settings.COCKPIT_PUBLIC_URL if hasattr(settings, "COCKPIT_PUBLIC_URL") else "http://10.4.7.18:8600"
    links = "\n".join(
        f"- {fmt.upper()}: {base}/api/packaging/download/{packaging_id}?format={fmt}"
        for fmt in ("svg", "png", "pdf")
    )
    email_body = (body.body or "").strip()
    if email_body:
        email_body += "\n\n"
    email_body += f"Packaging downloads:\n{links}"
    try:
        r = await _tools_request(
            "POST",
            "/emails/send",
            json={
                "to": body.to,
                "cc": body.cc,
                "subject": body.subject,
                "body": email_body,
                "client_id": body.client_id,
            },
        )
        r.raise_for_status()
        return r.json()
    except httpx.HTTPStatusError as exc:
        raise _tools_error(exc) from exc
