"""Scenario loader for Kiran/Concord.

Loads config/scenarios/domains.yaml and progression.yaml.
Casey flow: allies, challenges, decision points, scene updates.

Saturn Wave 6.
"""

from __future__ import annotations

from pathlib import Path
from typing import Any

import yaml


def _get_config_root() -> Path:
    """Project root (repo). Config resolution uses get_config_dir which respects data root."""
    return Path(__file__).resolve().parents[2]


def _config_dir() -> Path:
    from vastian.storage.data_root import get_config_dir

    return get_config_dir(_get_config_root())


def _load_yaml(path: Path) -> Any:
    if not path.exists():
        return None
    try:
        return yaml.safe_load(path.read_text(encoding="utf-8"))
    except Exception:
        return None


def load_scenario_domains() -> dict[str, Any]:
    """Load scenario domains from config/scenarios/domains.yaml."""
    path = _config_dir() / "scenarios" / "domains.yaml"
    data = _load_yaml(path)
    return data if isinstance(data, dict) else {}


def load_scenario_progression() -> dict[str, Any]:
    """Load scenario progression (levels, points) from config/scenarios/progression.yaml."""
    path = _config_dir() / "scenarios" / "progression.yaml"
    data = _load_yaml(path)
    return data if isinstance(data, dict) else {}


def load_scenario_challenges(team_id: int | None = None, tier: int = 1) -> list[dict]:
    """Load challenges from config/personas/ojas/challenges.yaml filtered by team_id and tier."""
    path = _config_dir() / "personas" / "ojas" / "challenges.yaml"
    data = _load_yaml(path)
    if not isinstance(data, list):
        return []
    result = []
    for c in data:
        if not isinstance(c, dict):
            continue
        if team_id is not None and c.get("team_id") != team_id:
            continue
        if c.get("tier", 1) != tier:
            continue
        result.append(dict(c))
    return result


def load_prompt_components(variant: str = "default") -> dict:
    """Load prompt components from config/scenarios/prompt_components/{variant}.yaml.

    Used to build scenario prompts.
    """
    path = _config_dir() / "scenarios" / "prompt_components" / f"{variant}.yaml"
    data = _load_yaml(path)
    return data if isinstance(data, dict) else {}


def load_metrics_definitions(owner: str | None = None) -> dict[str, dict]:
    """Load metric definitions from config/metrics/definitions.yaml.

    Args:
        owner: 'jake' returns only Jake's metrics, 'kiran' only Kiran's (Ojas). None = all.

    Returns:
        Dict of metric_id -> {name, formula, simulation_variable, category, phase, owner, description}
    """
    path = _config_dir() / "metrics" / "definitions.yaml"
    data = _load_yaml(path)
    if not isinstance(data, dict):
        return {}
    metrics = data.get("metrics", {})
    if not isinstance(metrics, dict):
        return {}
    result = {}
    for mid, m in metrics.items():
        if not isinstance(m, dict):
            continue
        m_owner = m.get("owner", "jake")
        if owner and m_owner != owner:
            continue
        result[mid] = dict(m)
        result[mid]["metric_id"] = mid
    return result


def load_metrics_baselines() -> dict[str, dict]:
    """Load default baselines from config/metrics/baselines.yaml."""
    path = _config_dir() / "metrics" / "baselines.yaml"
    data = _load_yaml(path)
    if not isinstance(data, dict):
        return {}
    return data.get("defaults", {})


def load_metrics_for_jake() -> list[str]:
    """Return metric IDs for Jake's validation set (all non-Ojas)."""
    path = _config_dir() / "metrics" / "domain_sets.yaml"
    data = _load_yaml(path)
    if not isinstance(data, dict):
        return []
    return list(data.get("jake_metrics", []))


def load_metrics_for_kiran() -> list[str]:
    """Return metric IDs for Kiran's Ojas metrics."""
    path = _config_dir() / "metrics" / "domain_sets.yaml"
    data = _load_yaml(path)
    if not isinstance(data, dict):
        return []
    return list(data.get("kiran_metrics", []))


def _metric_id_to_name(metric_id: str, definitions: dict | None = None) -> str:
    """Resolve metric_id to display name via definitions."""
    if definitions is None:
        definitions = load_metrics_definitions()
    m = definitions.get(metric_id, {})
    return m.get("name", metric_id.replace("_", " ").title())


def load_metrics_options(domain: str | None = None) -> list[str]:
    """Load metrics for a domain. Uses config/metrics/domain_sets.yaml + definitions for names.

    Args:
        domain: One of default, professional, personal, side_venture. None = default.

    Returns:
        List of metric display names for the domain.
    """
    path = _config_dir() / "metrics" / "domain_sets.yaml"
    data = _load_yaml(path)
    definitions = load_metrics_definitions()
    if isinstance(data, dict):
        key = (domain or "default").lower()
        metric_ids = data.get(key, data.get("default", []))
        if isinstance(metric_ids, list) and metric_ids:
            return [_metric_id_to_name(mid, definitions) for mid in metric_ids]
    # Fallback to legacy config/scenarios/metrics_options.yaml
    legacy = _config_dir() / "scenarios" / "metrics_options.yaml"
    leg_data = _load_yaml(legacy)
    if isinstance(leg_data, dict):
        key = (domain or "default").lower()
        metrics = leg_data.get(key, leg_data.get("default", []))
        if isinstance(metrics, list):
            return list(metrics)
    return []


def load_huddle_template(style: str = "labyrinth") -> dict:
    """Load huddle template by style from config/scenarios/prompt_templates/.

    Args:
        style: labyrinth, canvas, or portal.

    Returns:
        Template dict with components, challenge_emojis, flow. Empty dict if not found.
    """
    valid = ("labyrinth", "canvas", "portal")
    if style not in valid:
        style = "labyrinth"
    path = _config_dir() / "scenarios" / "prompt_templates" / f"huddle_{style}.yaml"
    data = _load_yaml(path)
    return data if isinstance(data, dict) else {}


def load_composed_prompt(style: str = "labyrinth") -> dict:
    """Load huddle template and merge all referenced components into one dict.

    Returns:
        Merged dict with template + all component contents for injection into Adrian prompt.
    """
    template = load_huddle_template(style)
    if not template:
        return {}
    components_list = template.get("components", [])
    pcdir = _config_dir() / "scenarios" / "prompt_components"
    merged: dict[str, Any] = dict(template)
    for name in components_list:
        path = pcdir / f"{name}.yaml"
        data = _load_yaml(path)
        if isinstance(data, dict):
            merged[f"component_{name}"] = data
    # Also load chat_cli_format for message structure
    chat = _load_yaml(pcdir / "chat_cli_format.yaml")
    if isinstance(chat, dict):
        merged["chat_cli_format"] = chat
    return merged


def format_composed_for_prompt(composed: dict) -> str:
    """Format composed prompt components as text for injection into Adrian's persona prompt."""
    if not composed:
        return ""
    parts = ["\n\n## Composed Structure (Casey Session Format — use this)"]
    w = composed.get("component_welcome", {})
    if isinstance(w, dict) and w.get("text"):
        parts.append(f"\n**Welcome**: {w['text']}")
    af = composed.get("component_allies_format", {})
    if isinstance(af, dict):
        if af.get("core_allies"):
            parts.append(f"\n**Core Allies**: {af['core_allies'].get('format', '')}")
        if af.get("supporting_forces"):
            parts.append(f"\n**Supporting Forces**: {af['supporting_forces'].get('format', '')}")
    cf = composed.get("chat_cli_format", {})
    if isinstance(cf, dict):
        parts.append(f"\n**Turn-taking**: {cf.get('turn_taking', '')}")
        dp = cf.get("decision_point", {})
        if isinstance(dp, dict):
            parts.append(f"\n**Decision point**: {dp.get('format', '')}")
        parts.append(f"\n**Scene update**: {cf.get('scene_update', '')}")
    emojis = composed.get("challenge_emojis", {})
    if emojis:
        parts.append(f"\n**Challenge emojis**: {emojis}")
    flow = composed.get("flow", [])
    if flow:
        parts.append(f"\n**Flow**: {' → '.join(flow)}")
    wrap = composed.get("component_wrap_up", {})
    if isinstance(wrap, dict) and wrap.get("variants"):
        v = wrap["variants"][0] if wrap["variants"] else {}
        parts.append(f"\n**Wrap-up heading**: {v.get('emoji', '')} {v.get('heading', '')}")
    return "".join(parts)


def load_casey_template() -> dict:
    """Load Casey scenario template from config/scenarios/templates/casey_scenario.yaml."""
    path = _config_dir() / "scenarios" / "templates" / "casey_scenario.yaml"
    data = _load_yaml(path)
    return data if isinstance(data, dict) else {}


def load_blueprint(blueprint_id: str) -> dict | None:
    """Load a success blueprint by ID from config/metrics/blueprints/."""
    path = _config_dir() / "metrics" / "blueprints" / f"{blueprint_id}.yaml"
    data = _load_yaml(path)
    if isinstance(data, dict):
        data["id"] = data.get("id", blueprint_id)
        return data
    return None


def load_all_blueprints() -> list[dict]:
    """Load all success blueprints from config/metrics/blueprints/."""
    bdir = _config_dir() / "metrics" / "blueprints"
    if not bdir.exists():
        return []
    result = []
    for f in sorted(bdir.glob("*.yaml")):
        data = _load_yaml(f)
        if isinstance(data, dict):
            data["id"] = data.get("id", f.stem)
            result.append(data)
    return result


def load_standard_scenarios() -> list[dict]:
    """Load standard (app-included) scenarios from config/scenarios/standard/.

    Note: These are *templates* — not shown to users directly.
    Use load_active_scenarios() for user-facing display.
    """
    sdir = _config_dir() / "scenarios" / "standard"
    if not sdir.exists():
        return []
    result = []
    for f in sorted(sdir.glob("*.yaml")):
        data = _load_yaml(f)
        if isinstance(data, dict):
            data["id"] = data.get("id", f.stem)
            data["source"] = "standard"
            result.append(data)
    return result


def load_active_scenarios() -> list[dict]:
    """Load agent-assigned scenarios from config/scenarios/active/.

    Only scenarios placed here by an agent (Victor, Concord) are shown to the user.
    Falls back to empty list if no active scenarios exist yet.
    """
    adir = _config_dir() / "scenarios" / "active"
    if not adir.exists():
        adir.mkdir(parents=True, exist_ok=True)
        return []
    result = []
    for f in sorted(adir.glob("*.yaml")):
        if f.stem.startswith("_"):
            continue
        data = _load_yaml(f)
        if isinstance(data, dict):
            data["id"] = data.get("id", f.stem)
            data["source"] = "active"
            result.append(data)
    return result


def load_scenario_by_id(scenario_id: str) -> dict | None:
    """Load a scenario by ID from active, standard, or config/scenarios/custom/."""
    cfg = _config_dir()
    for subdir in ("active", "standard", "custom"):
        path = cfg / "scenarios" / subdir / f"{scenario_id}.yaml"
        if path.exists():
            data = _load_yaml(path)
            if isinstance(data, dict):
                data["id"] = data.get("id", scenario_id)
                data["source"] = subdir
                return data
    return None
