"""Runtime role and task-model resolution."""

from __future__ import annotations

from dataclasses import dataclass

from scripts.lib.model_config import resolve_model_profile


ROLE_DEFAULTS = {
    "dr_plan": {
        "skills": ["document-ingest", "search-gateway", "search-strategy", "source-quality", "length-budget", "mckinsey-method"],
        "temperature": 0.4,
        "max_tokens": 12000,
        "max_concurrency": 1,
    },
    "dr_pm": {
        "skills": ["length-budget", "evidence-table", "mckinsey-method"],
        "temperature": 0.2,
        "max_tokens": 8000,
        "max_concurrency": 1,
    },
    "dr_searcher": {
        "skills": ["search-gateway", "search-strategy", "source-quality"],
        "temperature": 0.1,
        "max_tokens": 6000,
        "max_concurrency": 6,
    },
    "dr_analyst": {
        "skills": ["search-gateway", "search-strategy", "source-quality", "evidence-table", "mckinsey-method"],
        "temperature": 0.3,
        "max_tokens": 14000,
        "max_concurrency": 6,
    },
    "dr_verifier": {
        "skills": ["search-gateway", "search-strategy", "source-quality", "evidence-table"],
        "temperature": 0.2,
        "max_tokens": 10000,
        "max_concurrency": 4,
    },
    "dr_chief_editor": {
        "skills": ["mckinsey-method", "evidence-table", "output-hygiene"],
        "temperature": 0.2,
        "max_tokens": 16000,
        "max_concurrency": 1,
    },
    "dr_editor_in_chief": {
        "skills": ["mckinsey-method", "citation-manager", "humanizer-cn", "output-hygiene"],
        "temperature": 0.4,
        "max_tokens": 20000,
        "max_concurrency": 1,
    },
    "dr_reporter": {
        "skills": ["pdf-reportlab", "citation-manager", "output-hygiene"],
        "temperature": 0.1,
        "max_tokens": 6000,
        "max_concurrency": 1,
    },
}


ROLE_IDENTITIES = {
    "dr_plan": (
        "你是 Deep Research 的 Phase1 研究架构师。你的工作不是列目录，而是先消化材料、访谈和初步搜索，"
        "形成可被证伪的主判断、章节命题和求证路线。你要大胆假设，但必须给 Phase2 留下清晰的验证和推翻条件。"
    ),
    "dr_pm": (
        "你是 Deep Research 的研究项目经理。你的职责是把研究意图转化为可并发执行、可回收校验的任务，"
        "控制碎片化、重复检索和上下文污染。"
    ),
    "dr_searcher": (
        "你是 Deep Research 的信源发现员。你的职责是用短英文关键词和轴向词找到高质量入口，"
        "优先官方、法规、学术和一手材料；你不写结论，只交付可追溯来源。"
    ),
    "dr_analyst": (
        "你是 Deep Research 的章节证据分析师。你的职责不是写一篇像样的空泛文章，而是围绕 Phase1 命题"
        "小心求证：提取材料原文、检索权威证据、寻找反方边界，并把证据整理成可审计的结构化 packet。"
    ),
    "dr_verifier": (
        "你是 Deep Research 的独立反方审校员。你的默认姿态是质疑：找证据缺口、适用边界、反例和过度推断，"
        "并指出哪些结论必须降级或回炉。"
    ),
    "dr_chief_editor": (
        "你是 Deep Research 的 Phase3 总编审校。你的职责是通读 Phase1 假设与 Phase2 证据，判断二者是否自洽，"
        "优先指出结构性失败、证据不足和需要回炉的章节。"
    ),
    "dr_editor_in_chief": (
        "你是 Deep Research 的终稿主编。你的职责是把已验证证据组织成客户可读的中文报告，"
        "保持观点清晰、证据密实、表达克制，避免翻译腔和 AI 味。"
    ),
    "dr_reporter": (
        "你是 Deep Research 的报告制作负责人。你的职责是把已定稿内容可靠渲染为 PDF/DOCX，"
        "确保引用、排版、中文字体、表格和输出卫生可交付。"
    ),
}


@dataclass(frozen=True)
class RoleDefinition:
    name: str
    model: str
    skills: list[str]
    temperature: float
    max_tokens: int
    max_concurrency: int
    identity: str = ""


class RuntimeProfile:
    def __init__(self, *, profile: str, roles: dict[str, RoleDefinition], task_types: dict[str, str]) -> None:
        self.profile = profile
        self.roles = roles
        self.task_types = task_types

    def role_for_task(self, task_type: str) -> RoleDefinition:
        role_name = self.task_types.get(task_type)
        if not role_name:
            raise KeyError(f"unknown task_type: {task_type}")
        if role_name not in self.roles:
            raise KeyError(f"task_type {task_type} maps to missing role {role_name}")
        return self.roles[role_name]


def resolve_runtime_profile(
    *,
    profile: str | None = None,
    overrides: dict[str, str] | None = None,
) -> RuntimeProfile:
    resolved = resolve_model_profile(profile=profile, overrides=overrides)
    role_models = resolved["roles"]
    roles: dict[str, RoleDefinition] = {}
    for name, defaults in ROLE_DEFAULTS.items():
        model = role_models.get(name)
        if not model:
            continue
        roles[name] = RoleDefinition(
            name=name,
            model=model,
            skills=list(defaults["skills"]),
            temperature=float(defaults["temperature"]),
            max_tokens=int(defaults["max_tokens"]),
            max_concurrency=int(defaults["max_concurrency"]),
            identity=ROLE_IDENTITIES.get(name, ""),
        )
    return RuntimeProfile(
        profile=resolved["profile"],
        roles=roles,
        task_types=dict(resolved.get("task_types") or {}),
    )
