from __future__ import annotations

import json
import re
from pathlib import Path
from typing import Any


_PROMPT_DIR = Path(__file__).resolve().parent.parent / "nemoclaw_prompts"
_PLACEHOLDER_PATTERN = re.compile(r"\{(\w+)\}")
_TEMPLATE_HINTS = {
    "pipeline": ["tpl_pipeline_board_v2", "tpl_followup_queue_v1"],
    "kanban": ["tpl_pipeline_board_v2"],
    "map": ["tpl_geo_investor_heat_v2"],
    "geo": ["tpl_geo_investor_heat_v2"],
    "trend": ["tpl_absorption_trend_v1", "tpl_campaign_lead_line_v1"],
    "quota": ["tpl_quota_gauge_v1", "tpl_kpi_pipeline_health_v1"],
    "broker": ["tpl_broker_performance_v1"],
    "source": ["tpl_qd_source_compare_v1", "tpl_bar_source_quality_v3"],
    "follow": ["tpl_followup_queue_v1", "tpl_followup_gap_v1"],
    "campaign": ["tpl_campaign_lead_line_v1"],
}


class PersonaService:
    def __init__(self) -> None:
        self.prompt_files = {
            "qd_calculator": _PROMPT_DIR / "qd_calculator.md",
            "lead_tagger": _PROMPT_DIR / "lead_tagger.md",
            "cctv_profiler": _PROMPT_DIR / "cctv_profiler.md",
        }

    async def health(self) -> dict[str, Any]:
        loaded = {}
        for key, path in self.prompt_files.items():
            loaded[key] = path.exists() and path.read_text(encoding="utf-8").strip() != ""
        return {
            "status": "healthy" if all(loaded.values()) else "degraded",
            "prompts": loaded,
        }

    async def render_prompt(
        self,
        *,
        prompt_name: str,
        variables: dict[str, Any],
    ) -> dict[str, Any]:
        path = self.prompt_files.get(prompt_name)
        if path is None or not path.exists():
            raise FileNotFoundError(f"Unknown prompt '{prompt_name}'.")
        template = path.read_text(encoding="utf-8")
        rendered = template
        for key, value in variables.items():
            rendered = rendered.replace(f"{{{key}}}", json.dumps(value) if isinstance(value, (dict, list)) else str(value))
        unresolved = sorted(set(_PLACEHOLDER_PATTERN.findall(rendered)))
        return {
            "promptName": prompt_name,
            "templatePath": str(path),
            "renderedPrompt": rendered,
            "unresolvedVariables": unresolved,
        }

    async def plan_for_prompt(
        self,
        *,
        prompt: str,
        tenant_id: str,
        actor_role: str,
    ) -> dict[str, Any]:
        lower_prompt = prompt.lower()
        recommended: list[str] = []
        for token, template_ids in _TEMPLATE_HINTS.items():
            if token in lower_prompt:
                recommended.extend(template_ids)
        if not recommended:
            recommended = ["tpl_kpi_pipeline_health_v1", "tpl_qd_source_compare_v1"]
        recommended = list(dict.fromkeys(recommended))
        return {
            "tenantId": tenant_id,
            "actorRole": actor_role,
            "recommendedTemplates": recommended,
            "canvasBlocks": [
                {
                    "type": "textCanvas",
                    "widthMode": "full",
                    "minHeightPx": 180,
                    "content": (
                        "Oracle planned a mixed response: query the CRM, reuse matching component templates, "
                        "and synthesize missing visualization blocks if a direct template is unavailable."
                    ),
                }
            ],
            "workflowIntent": "comfy_oracle_canvas",
        }


persona_service = PersonaService()
