from __future__ import annotations
import json
from typing import Any
import httpx
from app.config import settings
from app.db import execute, fetch_one
from app.services import ollama
from app.services import packaging_agent
from app.services import webbuilder_agent
from app.services import voice_export_actions

AGENTS: dict[str, dict[str, str]] = {
    "marketing": {"name": "Marketing", "persona": "Social, brand voice, campaigns for Foodlinkk."},
    "bizdev": {"name": "BizDev", "persona": "Pipeline, retail partnerships, deal structuring."},
    "finance": {"name": "Finance", "persona": "Margins, cashflow, pricing for food brands."},
    "sourcing": {"name": "Sourcing", "persona": "Suppliers, MOQ, lead times, procurement."},
    "product": {"name": "Product", "persona": "SKU development, launch timelines, shelf readiness."},
    "halal": {"name": "Halal", "persona": "Halal compliance, certification, ingredient vetting."},
    "design": {"name": "Design", "persona": "Packaging, visual identity, retail presentation."},
    "packaging": {"name": "Packaging", "persona": "SVG/PDF verpakkingsontwerp, stanstekeningen, drukwerk."},
    "knowledge": {"name": "Knowledge", "persona": "Internal docs, RAG, policy answers."},
}


IMAGE_KEYWORDS = (
    "maak foto", "maak een foto", "genereer foto", "genereer afbeelding",
    "maak afbeelding", "productfoto", "genereer image", "generate image",
    "make image", "maak plaatje", "/genfoto",
)


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


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


async def _log_event(
    agent_name: str,
    event_type: str,
    title: str,
    body: str,
    metadata: dict | None = None,
    channel: str = "herman",
) -> None:
    payload = {
        "agent_name": agent_name,
        "agent_type": "herman_delegate",
        "event_type": event_type,
        "title": title[:255],
        "body": body,
        "metadata": metadata or {},
        "status": "completed",
        "channel": channel,
    }
    try:
        async with httpx.AsyncClient(timeout=15.0) as client:
            await client.post(f"{settings.TOOLS_API_URL.rstrip('/')}/events", json=payload)
    except Exception:
        try:
            execute(
                """INSERT INTO agent_events (agent_name, agent_type, event_type, title, body, status, channel, metadata)
                   VALUES (%s, %s, %s, %s, %s, %s, %s, %s::jsonb)""",
                (agent_name, "herman_delegate", event_type, title[:255], body, "completed", channel, json.dumps(metadata or {})),
            )
        except Exception:
            pass

def _pick_agent(raw: str) -> str:
    text = (raw or "").strip().lower()
    first = text.split()[0].replace(",", "").replace(".", "") if text else "knowledge"
    if first in AGENTS:
        return first
    for k in AGENTS:
        if k in text:
            return k
    return "knowledge"

def _agent_steps(delegated: list[str], routing_reason: str = "", extra: list[dict] | None = None) -> list[dict[str, str]]:
    steps: list[dict[str, str]] = []
    for a in delegated:
        key = (a or "").strip().lower()
        if key and key != "herman":
            steps.append({"agent": key, "status": "delegated", "message": routing_reason or "Aangestuurd door Herman"})
    if extra:
        steps.extend(extra)
    return steps


async def chat(
    message: str,
    channel: str = "cockpit",
    session_id: str | None = None,
    confirm_action_id: str | None = None,
) -> dict[str, Any]:
    use_voice_router = (
        channel in voice_export_actions.VOICE_CHANNELS
        or bool(session_id)
        or voice_export_actions.wants_export_search(message)
        or webbuilder_agent.wants_website(message)
    )
    if use_voice_router:
        routed = await voice_export_actions.handle_voice_command(
            message,
            session_id=session_id,
            confirm_action_id=confirm_action_id,
            channel=channel,
        )
        if routed is not None:
            await _log_event(
                "herman",
                "voice_command" if channel == "voice" else "browser_command",
                (routed.get("reply") or "")[:120],
                message[:2000],
                {
                    "pending_action": routed.get("pending_action"),
                    "ui_actions": routed.get("ui_actions"),
                    "channel": channel,
                },
                channel=channel,
            )
            return routed

    if webbuilder_agent.wants_website(message):
        try:
            outcome = await webbuilder_agent.generate_from_message(message, channel=channel, wait=False)
            project = outcome.get("project") or "website"
            preview = outcome.get("preview_url") or ""
            reply_lines = [
                f"Web Builder is gestart voor project **{project}**.",
                f"NAS: {outcome.get('nas_path') or '—'}",
                f"Preview (na afloop): {preview}",
                "Volg de live terminal: Agents → Terminals → Web Builder.",
            ]
            reply = "\n".join(reply_lines)
            await _log_event(
                "herman",
                "website_delegation",
                f"Herman → Web Builder: {project}",
                message[:2000],
                {
                    "delegated": ["webbuilder"],
                    "delegated_agents": ["webbuilder"],
                    "project": project,
                    "preview_url": preview,
                    "channel": channel,
                },
                channel=channel,
            )
            delegated = ["webbuilder"]
            return {
                "agent": "webbuilder",
                "agent_label": "Web Builder → Herman",
                "reply": reply,
                "delegated_agents": delegated,
                "routing_reason": "Website-opdracht — Web Builder gestart op Hermes/agy",
                "agent_steps": _agent_steps(delegated, "Website build gestart"),
                "webbuilder_project": project,
                "webbuilder_preview_url": preview,
                "ui_actions": [
                    {
                        "type": "open_webbuilder_build",
                        "title": f"Website build — {project}",
                        "project": project,
                        "preview_url": preview,
                        "nas_path": outcome.get("nas_path") or "",
                        "agents_url": "/agents",
                    }
                ],
            }
        except Exception as exc:
            await _log_event(
                "webbuilder",
                "website_build_error",
                "Website start mislukt",
                str(exc)[:1500],
                {"message": message[:500]},
            )
            return {
                "agent": "webbuilder",
                "agent_label": "Web Builder",
                "reply": f"Web Builder kon niet starten: {exc}",
                "delegated_agents": ["webbuilder"],
            }

    if packaging_agent.wants_packaging(message):
        try:
            outcome = await packaging_agent.generate_from_message(message)
            name = outcome.get("design_name") or "Design"
            pid = outcome.get("packaging_id", "")[:8]
            reply_lines = [
                f"Packaging agent heeft een design klaar voor je: {name}",
                f"Type: {outcome.get('type')} · {outcome.get('dimensions')}",
                f"Project #{outcome.get('cockpit_project_id')}",
                f"Studio: {outcome.get('studio_url')}",
                f"PDF: {outcome.get('pdf_url')}",
            ]
            if outcome.get("nas", {}).get("ok"):
                reply_lines.append("Bestanden staan op de NAS in de packaging-map van het project.")
            reply = "\n".join(reply_lines)

            await _log_event(
                "packaging",
                "packaging_created",
                f"Design klaar: {name}",
                f"Herman-opdracht: {message[:1500]}\n\nDesign-ID: {outcome.get('packaging_id')}",
                {
                    "packaging_id": outcome.get("packaging_id"),
                    "project_id": outcome.get("cockpit_project_id"),
                    "studio_url": outcome.get("studio_url"),
                    "pdf_url": outcome.get("pdf_url"),
                    "nas": outcome.get("nas"),
                    "for_herman": True,
                    "delegated": ["packaging"],
                    "channel": channel,
                },
                channel=channel,
            )
            await _log_event(
                "herman",
                "packaging_delivered",
                f"Packaging → Herman: {name}",
                reply[:2000],
                {
                    "source_agent": "packaging",
                    "packaging_id": outcome.get("packaging_id"),
                    "project_id": outcome.get("cockpit_project_id"),
                    "delegated": ["packaging"],
                    "channel": channel,
                },
                channel=channel,
            )
            delegated = ["packaging"]
            return {
                "agent": "packaging",
                "agent_label": "Packaging → Herman",
                "reply": reply,
                "delegated_agents": delegated,
                "routing_reason": "Packaging-opdracht gedetecteerd — design gegenereerd en aan Herman gerapporteerd",
                "agent_steps": _agent_steps(delegated, "Packaging design gegenereerd"),
                "packaging_id": outcome.get("packaging_id"),
                "packaging_studio_url": outcome.get("studio_url"),
                "packaging_pdf_url": outcome.get("pdf_url"),
            }
        except Exception as exc:
            await _log_event(
                "packaging",
                "packaging_error",
                "Packaging generatie mislukt",
                str(exc)[:1500],
                {"message": message[:500]},
            )
            return {
                "agent": "packaging",
                "agent_label": "Packaging",
                "reply": f"Packaging agent kon geen design maken: {exc}",
                "delegated_agents": ["packaging"],
            }

    if _wants_image(message):
        prompt = _extract_image_prompt(message)
        try:
            async with httpx.AsyncClient(timeout=620.0) as client:
                r = await client.post(
                    f"{settings.TOOLS_API_URL.rstrip('/')}/images/generate",
                    json={"prompt": prompt, "width": 512, "height": 512, "steps": 15},
                )
                r.raise_for_status()
                data = r.json()
            filename = data.get("filename", "")
            subfolder = data.get("subfolder", "")
            img_type = data.get("type", "output")
            proxy = f"/api/ai/generated-image?filename={filename}&subfolder={subfolder}&type={img_type}"
            reply = f"Afbeelding gegenereerd voor: {prompt}"
            await _log_event("design", "image_generated", "ComfyUI via Herman", prompt[:500], {"filename": filename, "channel": channel}, channel=channel)
            delegated = ["design"]
            return {
                "agent": "design",
                "agent_label": "Design",
                "reply": reply,
                "image_url": proxy,
                "prompt": prompt,
                "delegated_agents": delegated,
                "agent_steps": _agent_steps(delegated, "Afbeelding gegenereerd"),
            }
        except Exception as exc:
            return {
                "agent": "design",
                "agent_label": "Design",
                "reply": f"Kon geen afbeelding genereren: {exc}",
            }

    try:
        async with httpx.AsyncClient(timeout=620.0) as client:
            r = await client.post(
                f"{settings.HERMAN_ORCHESTRATOR_URL.rstrip('/')}/chat",
                json={"message": message, "agent": "default", "use_crm": True, "use_rag": True, "channel": channel},
            )
            r.raise_for_status()
            data = r.json()
        delegated = data.get("delegated_agents") or [data.get("agent", "herman")]
        reason = data.get("routing_reason", "") or ""
        await _log_event(
            "herman",
            "voice_delegation" if channel == "voice" else ("telegram_delegation" if channel == "telegram" else "openswarm_delegation"),
            f"Herman → {', '.join(delegated)}",
            message[:2000],
            {"delegated": delegated, "delegated_agents": delegated, "reason": reason, "channel": channel},
            channel=channel,
        )
        return {
            "agent": data.get("agent", "herman"),
            "agent_label": data.get("agent_label", "Herman"),
            "reply": data.get("reply", ""),
            "delegated_agents": delegated,
            "routing_reason": reason,
            "agent_steps": _agent_steps(delegated, reason),
            "rag_sources": data.get("rag_sources") or [],
            "crm_loaded": data.get("crm_loaded", False),
        }
    except Exception as exc:
        return {
            "agent": "herman",
            "agent_label": "Herman",
            "reply": f"Herman orchestrator niet bereikbaar: {exc}",
        }

async def generate_briefing() -> str:
    from app.services.briefing import generate_daily_briefing
    content, stats = await generate_daily_briefing()
    await _log_event("herman", "briefing", "CEO briefing generated", content[:1500], {"stats": stats})
    return content