"""Packaging agent — parse Herman-opdrachten en genereer designs."""
from __future__ import annotations

import re
from typing import Any

import httpx

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

PACKAGING_KEYWORDS = (
    "maak verpakking",
    "maak een verpakking",
    "genereer verpakking",
    "ontwerp verpakking",
    "packaging:",
    "packaging ",
    "/packaging",
    "maak packaging",
    "maak package",
    "stanstekening",
    "verpakkingsontwerp",
)

TYPE_ALIASES: list[tuple[str, str]] = [
    ("folding box", "folding_box"),
    ("folding_box", "folding_box"),
    ("sluitdoos", "folding_box"),
    ("doos", "folding_box"),
    ("banderole", "wrap"),
    ("wrap", "wrap"),
    ("rond label", "round_label"),
    ("round label", "round_label"),
    ("round_label", "round_label"),
    ("sleeve", "sleeve"),
    ("huls", "sleeve"),
    ("pouch", "pouch"),
    ("zak", "pouch"),
    ("tray", "tray"),
    ("schaal", "tray"),
]

DEFAULT_ELEMENTS = {
    "barcode": True,
    "logo_area": True,
    "fold_lines": True,
    "cut_lines": True,
    "nutrition_panel": False,
    "ingredients": True,
    "halal_badge": False,
    "window": False,
    "qr_code": False,
    "glue_tabs": False,
    "bleed": True,
    "dimensions": True,
}


def wants_packaging(raw: str) -> bool:
    t = (raw or "").strip().lower()
    return any(k in t for k in PACKAGING_KEYWORDS)


def extract_packaging_body(raw: str) -> str:
    t = raw.strip()
    lower = t.lower()
    for k in PACKAGING_KEYWORDS:
        if lower.startswith(k):
            rest = t[len(k) :].strip(" :,-")
            if rest:
                return rest
    for k in PACKAGING_KEYWORDS:
        if k in lower:
            idx = lower.index(k) + len(k)
            rest = t[idx:].strip(" :,-")
            if rest:
                return rest
    return t


def _detect_type(text: str) -> str:
    lower = text.lower()
    for alias, ptype in TYPE_ALIASES:
        if alias in lower:
            return ptype
    return "folding_box"


def _detect_dimensions(text: str) -> tuple[float, float, float]:
    m = re.search(r"(\d{2,4})\s*[x×]\s*(\d{2,4})(?:\s*[x×]\s*(\d{1,4}))?", text, re.I)
    if m:
        w, h = float(m.group(1)), float(m.group(2))
        d = float(m.group(3)) if m.group(3) else (40.0 if _detect_type(text) == "folding_box" else 20.0)
        return w, h, d
    return 120.0, 80.0, 40.0


def _detect_project_id(text: str) -> int | None:
    m = re.search(r"project\s*#?\s*(\d+)", text, re.I)
    if m:
        return int(m.group(1))
    m = re.search(r"\bproject\s+(\d+)\b", text, re.I)
    return int(m.group(1)) if m else None


def _detect_product_name(text: str) -> str:
    m = re.search(r'voor\s+["\']?([^"\']+?)["\']?(?:\s+project|\s*$|,)', text, re.I)
    if m:
        return m.group(1).strip()[:80]
    m = re.search(r'product\s*[:=]\s*["\']?([^"\']+)["\']?', text, re.I)
    if m:
        return m.group(1).strip()[:80]
    cleaned = text
    for alias, _ in TYPE_ALIASES:
        cleaned = re.sub(re.escape(alias), "", cleaned, flags=re.I)
    cleaned = re.sub(r"\d{2,4}\s*[x×]\s*\d{2,4}(?:\s*[x×]\s*\d{1,4})?", "", cleaned, flags=re.I)
    cleaned = re.sub(r"project\s*#?\s*\d+", "", cleaned, flags=re.I)
    for kw in ("halal-badge", "halal badge", "voedingswaarden", "nutrition", "qr-code", "qr code", "venster", "window"):
        cleaned = re.sub(re.escape(kw), "", cleaned, flags=re.I)
    cleaned = cleaned.strip(" ,:-")
    return (cleaned[:80] or "Foodlinkk Product")


def parse_packaging_request(message: str) -> dict[str, Any]:
    body = extract_packaging_body(message)
    lower = body.lower()
    ptype = _detect_type(body)
    w, h, d = _detect_dimensions(body)
    product = _detect_product_name(body)
    project_id = _detect_project_id(message) or _detect_project_id(body)

    elements = dict(DEFAULT_ELEMENTS)
    if any(k in lower for k in ("halal", "halal-badge", "halal badge")):
        elements["halal_badge"] = True
    if any(k in lower for k in ("voedingswaarden", "nutrition")):
        elements["nutrition_panel"] = True
    if any(k in lower for k in ("qr", "qrcode")):
        elements["qr_code"] = True
    if "venster" in lower or "window" in lower:
        elements["window"] = True

    return {
        "type": ptype,
        "width_mm": w,
        "height_mm": h,
        "depth_mm": d,
        "bleed_mm": 3,
        "design_name": product,
        "barcode_value": "8710000000012",
        "elements": elements,
        "text": {
            "product_name": product,
            "tagline": "Premium halal kant-en-klaar",
            "subtitle": "",
            "ingredients": "",
            "origin": "Geproduceerd in NL",
            "best_before": "Ten minste houdbaar tot: zie verpakking",
        },
        "brand": {},
        "project_id": project_id,
        "created_by": "packaging",
    }


async def _download_bytes(packaging_id: str, fmt: str) -> bytes | None:
    try:
        async with httpx.AsyncClient(timeout=120.0) as client:
            r = await client.get(
                f"{settings.TOOLS_API_URL.rstrip('/')}/packaging/download/{packaging_id}",
                params={"format": fmt},
            )
            if r.status_code < 400:
                return r.content
    except Exception:
        pass
    return None


async def generate_from_message(message: str) -> dict[str, Any]:
    """Genereer packaging design en exporteer naar NAS; retour voor Herman-reply."""
    spec = parse_packaging_request(message)

    if not spec.get("project_id"):
        proj = projects.create_project(
            f"Packaging · {spec['design_name'][:48]}",
            description=f"Aangemaakt door packaging agent via Herman\n\nOpdracht: {message[:500]}",
            project_type="packaging",
            ensure_nas=True,
            created_by="packaging",
        )
        spec["project_id"] = proj.get("id")

    async with httpx.AsyncClient(timeout=120.0) as client:
        r = await client.post(
            f"{settings.TOOLS_API_URL.rstrip('/')}/packaging/generate",
            json=spec,
        )
        r.raise_for_status()
        result = r.json()

    packaging_id = result.get("id", "")
    cockpit_project_id = result.get("cockpit_project_id") or spec.get("project_id")
    svg = result.get("svg") or ""
    saved_spec = result.get("spec") or spec

    nas_info: dict[str, Any] = {}
    if packaging_id and cockpit_project_id and svg:
        png_b = await _download_bytes(packaging_id, "png")
        pdf_b = await _download_bytes(packaging_id, "pdf")
        try:
            nas_info = packaging_nas.export_packaging_files(
                packaging_id, int(cockpit_project_id), svg, saved_spec, png_b, pdf_b
            )
        except Exception as exc:
            nas_info = {"ok": False, "error": str(exc)}

    studio_url = f"/packaging?project_id={cockpit_project_id}"
    pdf_url = f"/api/packaging/download/{packaging_id}?format=pdf"

    return {
        "packaging_id": packaging_id,
        "cockpit_project_id": cockpit_project_id,
        "design_name": saved_spec.get("design_name") or spec.get("design_name"),
        "type": saved_spec.get("type"),
        "dimensions": f"{saved_spec.get('width_mm')}×{saved_spec.get('height_mm')}×{saved_spec.get('depth_mm')} mm",
        "studio_url": studio_url,
        "pdf_url": pdf_url,
        "nas": nas_info,
        "spec": saved_spec,
        "original_message": message,
    }
