"""Voice/browser/Telegram command router: export intel, webbuilder/agy, bevestiging + UI."""
from __future__ import annotations

import re
import time
import uuid
from typing import Any

import httpx

from app.config import settings
from app.services import webbuilder_agent

SESSION_TTL_SEC = 3600
_pending: dict[str, dict[str, Any]] = {}

VOICE_CHANNELS = frozenset({"voice", "browser", "telegram"})

LOCATION_ALIASES: dict[str, dict[str, str]] = {
    "dubai": {"country": "AE", "q": "Dubai", "label": "Dubai (VAE)"},
    "abu dhabi": {"country": "AE", "q": "Abu Dhabi", "label": "Abu Dhabi (VAE)"},
    "sharjah": {"country": "AE", "q": "Sharjah", "label": "Sharjah (VAE)"},
    "vae": {"country": "AE", "q": "", "label": "Verenigde Arabische Emiraten"},
    "uae": {"country": "AE", "q": "", "label": "Verenigde Arabische Emiraten"},
    "emiraten": {"country": "AE", "q": "", "label": "VAE"},
    "saudi": {"country": "SA", "q": "", "label": "Saoedi-Arabië"},
    "riyadh": {"country": "SA", "q": "Riyadh", "label": "Riyadh (SA)"},
    "jeddah": {"country": "SA", "q": "Jeddah", "label": "Jeddah (SA)"},
    "qatar": {"country": "QA", "q": "", "label": "Qatar"},
    "doha": {"country": "QA", "q": "Doha", "label": "Doha (Qatar)"},
    "kuwait": {"country": "KW", "q": "", "label": "Koeweit"},
    "nederland": {"country": "NL", "q": "", "label": "Nederland"},
    "amsterdam": {"country": "NL", "q": "Amsterdam", "label": "Amsterdam"},
    "rotterdam": {"country": "NL", "q": "Rotterdam", "label": "Rotterdam"},
    "belgië": {"country": "BE", "q": "", "label": "België"},
    "belgie": {"country": "BE", "q": "", "label": "België"},
    "antwerpen": {"country": "BE", "q": "Antwerp", "label": "Antwerpen"},
    "duitsland": {"country": "DE", "q": "", "label": "Duitsland"},
    "berlijn": {"country": "DE", "q": "Berlin", "label": "Berlijn"},
    "frankfurt": {"country": "DE", "q": "Frankfurt", "label": "Frankfurt"},
    "turkije": {"country": "TR", "q": "", "label": "Turkije"},
    "istanbul": {"country": "TR", "q": "Istanbul", "label": "Istanbul"},
    "marokko": {"country": "MA", "q": "", "label": "Marokko"},
    "casablanca": {"country": "MA", "q": "Casablanca", "label": "Casablanca"},
}

ENTITY_ALIASES: dict[str, str] = {
    "distri": "distributor,wholesaler,importer,logistics",
    "distributeur": "distributor,wholesaler,importer,logistics",
    "distributeurs": "distributor,wholesaler,importer,logistics",
    "groothandel": "wholesaler,distributor",
    "groothandels": "wholesaler,distributor",
    "importeur": "importer",
    "importeurs": "importer",
    "logistiek": "logistics",
    "restaurant": "restaurant",
    "restaurants": "restaurant",
    "cateraar": "caterer",
    "cateraars": "caterer",
    "slager": "butcher",
    "slagers": "butcher",
    "döner": "doner",
    "doner": "doner",
}

SEARCH_TRIGGERS = (
    "zoek", "opzoeken", "vind", "zoeken", "toon", "laat zien", "lijst",
    "geef me", "haal op", "export intel", "wereldexport",
)

YES_RE = re.compile(
    r"^(ja|jawel|jep|yep|ok|oke|oké|okay|klopt|bevestig|doe maar|graag|precies|goed|akkoord|start|uitvoeren|doorgaan)\b",
    re.I,
)
NO_RE = re.compile(r"^(nee|neen|stop|annuleer|niet|cancel|laat maar|wacht)\b", re.I)


def _cleanup_sessions() -> None:
    now = time.time()
    dead = [k for k, v in _pending.items() if now - float(v.get("_ts", 0)) > SESSION_TTL_SEC]
    for k in dead:
        _pending.pop(k, None)


def is_confirmation_yes(text: str) -> bool:
    t = (text or "").strip()
    return bool(t and YES_RE.search(t))


def is_confirmation_no(text: str) -> bool:
    t = (text or "").strip()
    return bool(t and NO_RE.search(t))


def wants_export_search(text: str) -> bool:
    t = (text or "").lower()
    if not any(k in t for k in SEARCH_TRIGGERS):
        return False
    has_loc = any(alias in t for alias in LOCATION_ALIASES)
    has_ent = any(alias in t for alias in ENTITY_ALIASES)
    return has_loc or has_ent


def _detect_location(text: str) -> dict[str, str] | None:
    t = text.lower()
    best: tuple[int, dict[str, str]] | None = None
    for alias, loc in LOCATION_ALIASES.items():
        if alias in t:
            score = len(alias)
            if best is None or score > best[0]:
                best = (score, loc)
    return best[1] if best else None


def _detect_entity_types(text: str) -> str:
    t = text.lower()
    found: list[str] = []
    for alias, types in ENTITY_ALIASES.items():
        if alias in t:
            for et in types.split(","):
                if et not in found:
                    found.append(et)
    if not found and any(w in t for w in ("distri", "distributeur", "groothandel", "b2b", "leverancier")):
        return "distributor,wholesaler,importer,logistics"
    return ",".join(found) if found else "distributor,wholesaler,importer,logistics"


def _entity_label(entity_types: str) -> str:
    labels = {
        "distributor": "distributeurs",
        "wholesaler": "groothandels",
        "importer": "importeurs",
        "logistics": "logistiek",
        "restaurant": "restaurants",
        "caterer": "cateraars",
        "butcher": "slagers",
        "doner": "dönerzaken",
    }
    parts = [labels.get(x.strip(), x.strip()) for x in entity_types.split(",") if x.strip()]
    return ", ".join(parts) if parts else "bedrijven"


def parse_export_search(text: str) -> dict[str, Any]:
    loc = _detect_location(text)
    entity_types = _detect_entity_types(text)
    missing: list[str] = []
    if not loc:
        missing.append("locatie")
    params: dict[str, Any] = {
        "country": (loc or {}).get("country", ""),
        "q": (loc or {}).get("q", ""),
        "entity_types": entity_types,
        "limit": 50,
    }
    label_loc = (loc or {}).get("label", "")
    return {
        "params": params,
        "location_label": label_loc,
        "entity_label": _entity_label(entity_types),
        "missing": missing,
        "incomplete": bool(missing),
    }


def store_pending(session_id: str, action: dict[str, Any]) -> str:
    _cleanup_sessions()
    action_id = str(uuid.uuid4())[:12]
    action = dict(action)
    action["id"] = action_id
    action["_ts"] = time.time()
    _pending[session_id] = action
    return action_id


def get_pending(session_id: str) -> dict[str, Any] | None:
    _cleanup_sessions()
    row = _pending.get(session_id)
    if not row:
        return None
    if time.time() - float(row.get("_ts", 0)) > SESSION_TTL_SEC:
        _pending.pop(session_id, None)
        return None
    return row


def clear_pending(session_id: str) -> None:
    _pending.pop(session_id, None)


def build_confirmation_question(parsed: dict[str, Any]) -> str:
    loc = parsed.get("location_label") or "de geselecteerde regio"
    ent = parsed.get("entity_label") or "bedrijven"
    return (
        f"Ik ga **{ent}** in **{loc}** voor je opzoeken in Export Intel.\n\n"
        "Klopt dat? Zeg **ja** om te starten, **nee** om te annuleren, "
        "of geef aan wat ik moet aanpassen (bijv. alleen distributeurs, of een andere stad)."
    )


def build_clarification_question(parsed: dict[str, Any]) -> str:
    missing = parsed.get("missing") or []
    if "locatie" in missing:
        return (
            "In welke **stad of welk land** wil je zoeken? "
            "Bijvoorbeeld: Dubai, VAE, Nederland, Frankfurt…"
        )
    return "Kun je iets specifieker zijn over wat je zoekt en waar?"


async def fetch_export_entities(params: dict[str, Any]) -> dict[str, Any]:
    query = {k: v for k, v in params.items() if v not in (None, "")}
    url = f"{settings.TOOLS_API_URL.rstrip('/')}/export-intel/entities"
    async with httpx.AsyncClient(timeout=60.0) as client:
        resp = await client.get(url, params=query)
        resp.raise_for_status()
        return resp.json()


def _open_url(params: dict[str, Any]) -> str:
    qs = []
    if params.get("country"):
        qs.append(f"country={params['country']}")
    if params.get("q"):
        qs.append(f"q={params['q']}")
    qs.append("tab=distributors")
    return "/export-intel?" + "&".join(qs)


async def execute_search_action(action: dict[str, Any]) -> dict[str, Any]:
    params = action.get("params") or {}
    data = await fetch_export_entities(params)
    items = data.get("items") or []
    total = int(data.get("total") or len(items))
    loc = action.get("location_label") or params.get("q") or params.get("country") or "markt"
    ent = action.get("entity_label") or "bedrijven"
    title = f"{ent.title()} — {loc}"
    if not items:
        reply = (
            f"Ik heb gezocht maar vond **geen** {ent} in {loc}. "
            "Wil je dat ik een sync start of een bredere regio probeer?"
        )
    else:
        reply = (
            f"Gevonden: **{total}** {ent} in {loc}. "
            f"Ik toon de eerste {min(len(items), 50)} in het resultatenvenster."
        )
    return {
        "agent": "sourcing",
        "agent_label": "Export Intel → Herman",
        "reply": reply,
        "delegated_agents": ["sourcing", "export_intel"],
        "routing_reason": f"Export Intel zoekopdracht: {title}",
        "agent_steps": [
            {"agent": "export_intel", "status": "done", "message": f"{total} resultaten"},
            {"agent": "sourcing", "status": "delegated", "message": "Marktdata opgehaald"},
        ],
        "needs_confirmation": False,
        "ui_actions": [
            {
                "type": "show_export_results",
                "title": title,
                "entities": items[:50],
                "total": total,
                "params": params,
                "open_url": _open_url(params),
            }
        ],
    }


def _pending_summary(action: dict[str, Any]) -> dict[str, Any]:
    atype = action.get("type", "")
    base = {"id": action.get("id"), "type": atype}
    if atype == "export_intel_search":
        base["location_label"] = action.get("location_label")
        base["entity_label"] = action.get("entity_label")
        base["params"] = action.get("params")
    elif atype == "webbuilder_build":
        base["project"] = action.get("project")
        base["entity_label"] = f"website {action.get('project', '')}"
        base["location_label"] = "Agy · Antigravity"
    return base


def build_webbuilder_confirmation(project: str, raw: str) -> str:
    snippet = (raw or "")[:240]
    return (
        f"Ik stuur **Agy (Antigravity)** op Hermes aan om een website te bouwen.\n\n"
        f"**Project:** {project}\n"
        f"**Opdracht:** {snippet}{'…' if len(raw or '') > 240 else ''}\n\n"
        "Klopt dat? Zeg **ja** om te starten, **nee** om te annuleren."
    )


async def execute_webbuilder_action(action: dict[str, Any], channel: str = "voice") -> dict[str, Any]:
    raw = action.get("raw_message") or ""
    project = action.get("project") or webbuilder_agent.extract_project_name(raw)
    try:
        outcome = await webbuilder_agent.generate_from_message(raw, channel=channel, wait=False)
    except Exception as exc:
        return {
            "agent": "webbuilder",
            "agent_label": "Web Builder",
            "reply": f"Agy kon niet starten op Hermes: {exc}\n\nControleer VM107 webbuilder-api (:8798).",
            "delegated_agents": ["webbuilder"],
            "needs_confirmation": False,
        }

    project = outcome.get("project") or project
    preview = outcome.get("preview_url") or webbuilder_agent.HERMES_PREVIEW_BASE
    nas_path = outcome.get("nas_path") or ""
    reply = (
        f"Agy is gestart voor **{project}**.\n"
        f"Preview (na build): {preview}\n"
        f"NAS: {nas_path}\n"
        "Volg live: Agents → Terminals → Web Builder."
    )
    return {
        "agent": "webbuilder",
        "agent_label": "Agy / Web Builder → Herman",
        "reply": reply,
        "delegated_agents": ["webbuilder"],
        "routing_reason": "Website via Antigravity CLI (agy) op Hermes VM107",
        "agent_steps": [
            {"agent": "webbuilder", "status": "running", "message": f"agy bouwt {project}"},
            {"agent": "herman", "status": "delegated", "message": "Voice → build gestart"},
        ],
        "webbuilder_project": project,
        "webbuilder_preview_url": preview,
        "needs_confirmation": False,
        "ui_actions": [
            {
                "type": "open_webbuilder_build",
                "title": f"Website build — {project}",
                "project": project,
                "preview_url": preview,
                "nas_path": nas_path,
                "agents_url": "/agents",
                "status_hint": "Build duurt enkele minuten — preview opent na afloop",
            }
        ],
    }


async def execute_pending_action(action: dict[str, Any], channel: str = "voice") -> dict[str, Any]:
    atype = action.get("type")
    if atype == "webbuilder_build":
        return await execute_webbuilder_action(action, channel=channel)
    return await execute_search_action(action)


def _confirmation_reminder(pending: dict[str, Any]) -> str:
    if pending.get("type") == "webbuilder_build":
        return build_webbuilder_confirmation(pending.get("project", "website"), pending.get("raw_message", ""))
    return build_confirmation_question(pending)


async def handle_voice_command(
    message: str,
    session_id: str | None = None,
    confirm_action_id: str | None = None,
    channel: str = "voice",
) -> dict[str, Any] | None:
    """Unified voice/browser router: bevestiging + export + webbuilder/agy."""
    sid = (session_id or "").strip() or "default"
    text = (message or "").strip()
    if not text:
        return None

    pending = get_pending(sid)

    if confirm_action_id and pending and pending.get("id") == confirm_action_id:
        clear_pending(sid)
        return await execute_pending_action(pending, channel=channel)

    if pending:
        if is_confirmation_yes(text):
            clear_pending(sid)
            return await execute_pending_action(pending, channel=channel)
        if is_confirmation_no(text):
            clear_pending(sid)
            return {
                "agent": "herman",
                "agent_label": "Herman",
                "reply": "Oké, geannuleerd. Waar kan ik je verder mee helpen?",
                "needs_confirmation": False,
            }
        if pending.get("awaiting") == "location" and pending.get("type") == "export_intel_search":
            loc = _detect_location(text)
            if loc:
                merged = dict(pending)
                merged["params"] = dict(pending.get("params") or {})
                merged["params"]["country"] = loc["country"]
                merged["params"]["q"] = loc.get("q", "")
                merged["location_label"] = loc["label"]
                merged.pop("awaiting", None)
                merged.pop("incomplete", None)
                merged.pop("missing", None)
                action_id = store_pending(sid, merged)
                return {
                    "agent": "herman",
                    "agent_label": "Herman",
                    "reply": build_confirmation_question(merged),
                    "needs_confirmation": True,
                    "pending_action": _pending_summary(merged),
                }
            return {
                "agent": "herman",
                "agent_label": "Herman",
                "reply": build_clarification_question({"missing": ["locatie"]}),
                "needs_confirmation": True,
                "clarification": True,
            }
        if webbuilder_agent.wants_website(text):
            project = webbuilder_agent.extract_project_name(text)
            action_id = store_pending(sid, {
                "type": "webbuilder_build",
                "project": project,
                "raw_message": text,
            })
            return {
                "agent": "herman",
                "agent_label": "Herman",
                "reply": build_webbuilder_confirmation(project, text),
                "needs_confirmation": True,
                "pending_action": _pending_summary(get_pending(sid) or {}),
            }
        if wants_export_search(text):
            parsed = parse_export_search(text)
            if not parsed.get("incomplete"):
                action_id = store_pending(sid, {**parsed, "type": "export_intel_search"})
                return {
                    "agent": "herman",
                    "agent_label": "Herman",
                    "reply": build_confirmation_question(parsed),
                    "needs_confirmation": True,
                    "pending_action": _pending_summary(get_pending(sid) or {}),
                }
        return {
            "agent": "herman",
            "agent_label": "Herman",
            "reply": (
                f"Ik wacht nog op bevestiging.\n\n{_confirmation_reminder(pending)}\n\n"
                "Zeg **ja** of **nee**."
            ),
            "needs_confirmation": True,
            "pending_action": _pending_summary(pending),
        }

    if webbuilder_agent.wants_website(text):
        project = webbuilder_agent.extract_project_name(text)
        store_pending(sid, {"type": "webbuilder_build", "project": project, "raw_message": text})
        pa = get_pending(sid) or {}
        return {
            "agent": "herman",
            "agent_label": "Herman",
            "reply": build_webbuilder_confirmation(project, text),
            "needs_confirmation": True,
            "pending_action": _pending_summary(pa),
        }

    return await handle_export_intent(message, session_id=session_id, confirm_action_id=confirm_action_id)


async def handle_export_intent(
    message: str,
    session_id: str | None = None,
    confirm_action_id: str | None = None,
) -> dict[str, Any] | None:
    """Return Herman-shaped dict when export flow applies, else None."""
    sid = (session_id or "").strip() or "default"
    text = (message or "").strip()
    if not text:
        return None

    pending = get_pending(sid)

    if confirm_action_id and pending and pending.get("id") == confirm_action_id:
        clear_pending(sid)
        return await execute_pending_action(pending)

    if pending:
        if is_confirmation_yes(text):
            clear_pending(sid)
            return await execute_pending_action(pending)
        if is_confirmation_no(text):
            clear_pending(sid)
            return {
                "agent": "herman",
                "agent_label": "Herman",
                "reply": "Oké, geannuleerd. Waar kan ik je verder mee helpen?",
                "needs_confirmation": False,
            }
        if pending.get("awaiting") == "location":
            loc = _detect_location(text)
            if loc:
                merged = dict(pending)
                merged["params"] = dict(pending.get("params") or {})
                merged["params"]["country"] = loc["country"]
                merged["params"]["q"] = loc.get("q", "")
                merged["location_label"] = loc["label"]
                merged.pop("awaiting", None)
                merged.pop("incomplete", None)
                merged.pop("missing", None)
                action_id = store_pending(sid, merged)
                return {
                    "agent": "herman",
                    "agent_label": "Herman",
                    "reply": build_confirmation_question(merged),
                    "needs_confirmation": True,
                    "pending_action": {
                        "id": action_id,
                        "type": "export_intel_search",
                        "params": merged.get("params"),
                        "location_label": merged.get("location_label"),
                        "entity_label": merged.get("entity_label"),
                    },
                }
            return {
                "agent": "herman",
                "agent_label": "Herman",
                "reply": build_clarification_question({"missing": ["locatie"]}),
                "needs_confirmation": True,
                "clarification": True,
            }
        if wants_export_search(text):
            parsed = parse_export_search(text)
            if parsed.get("incomplete"):
                return {
                    "agent": "herman",
                    "agent_label": "Herman",
                    "reply": build_clarification_question(parsed),
                    "needs_confirmation": True,
                    "clarification": True,
                }
            action_id = store_pending(sid, parsed)
            return {
                "agent": "herman",
                "agent_label": "Herman",
                "reply": build_confirmation_question(parsed),
                "needs_confirmation": True,
                "pending_action": {
                    "id": action_id,
                    "type": "export_intel_search",
                    "params": parsed.get("params"),
                    "location_label": parsed.get("location_label"),
                    "entity_label": parsed.get("entity_label"),
                },
            }
        return {
            "agent": "herman",
            "agent_label": "Herman",
            "reply": (
                f"Ik wacht nog op bevestiging: {build_confirmation_question(pending)}\n\n"
                "Zeg **ja** of **nee**, of stel een nieuwe zoekopdracht."
            ),
            "needs_confirmation": True,
            "pending_action": {
                "id": pending.get("id"),
                "type": pending.get("type", "export_intel_search"),
                "params": pending.get("params"),
                "location_label": pending.get("location_label"),
                "entity_label": pending.get("entity_label"),
            },
        }

    if not wants_export_search(text):
        return None

    parsed = parse_export_search(text)
    if parsed.get("incomplete"):
        store_pending(sid, {**parsed, "type": "export_intel_search", "awaiting": "location"})
        return {
            "agent": "herman",
            "agent_label": "Herman",
            "reply": build_clarification_question(parsed),
            "needs_confirmation": True,
            "clarification": True,
        }

    action_id = store_pending(sid, {**parsed, "type": "export_intel_search"})
    return {
        "agent": "herman",
        "agent_label": "Herman",
        "reply": build_confirmation_question(parsed),
        "needs_confirmation": True,
        "pending_action": {
            "id": action_id,
            "type": "export_intel_search",
            "params": parsed.get("params"),
            "location_label": parsed.get("location_label"),
            "entity_label": parsed.get("entity_label"),
        },
    }
