"""subject_matured detection — state/subject/meta.yaml."""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

import yaml

from niannian.soul.subject_store import SubjectStateStore

_META_FILENAME = "meta.yaml"
_NARRATIVE_ELIGIBLE_MIN = 3
_EVOLUTION_PROMOTE_MIN = 1
_ATOM_COUNT_MIN = 50
_DREAM_RUN_MIN = 3


def meta_path(home: Path) -> Path:
    return SubjectStateStore(home).subject_root / _META_FILENAME


def load_subject_meta(home: Path) -> dict[str, Any]:
    path = meta_path(home)
    if not path.is_file():
        return {}
    with path.open(encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}
    return data if isinstance(data, dict) else {}


def save_subject_meta(home: Path, data: dict[str, Any]) -> None:
    path = meta_path(home)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(yaml.safe_dump(data, allow_unicode=True, sort_keys=False), encoding="utf-8")


def _count_narrative_eligible(store: SubjectStateStore) -> int:
    narrative = store.load_narrative()
    count = 0
    for line in narrative.get("lines") or []:
        if not isinstance(line, dict):
            continue
        if line.get("subject_eligible") is True:
            count += 1
    return count


def _count_evolution_promotes(store: SubjectStateStore) -> int:
    path = store.subject_root / "evolution.jsonl"
    if not path.is_file():
        return 0
    count = 0
    for raw in path.read_text(encoding="utf-8").splitlines():
        raw = raw.strip()
        if not raw:
            continue
        try:
            row = json.loads(raw)
        except json.JSONDecodeError:
            continue
        action = str(row.get("action") or "")
        if action in {"promote", "adopt", "F9_promote"}:
            count += 1
    return count


def _count_subject_atoms(home: Path) -> int:
    atoms_path = home / "left" / "atoms.jsonl"
    if not atoms_path.is_file():
        return 0
    count = 0
    for line in atoms_path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line:
            continue
        try:
            row = json.loads(line)
        except json.JSONDecodeError:
            continue
        meta = row.get("meta") or {}
        if meta.get("memory_scope") == "subject" or meta.get("subject_eligible") is True:
            count += 1
    return count


def _count_dream_runs(home: Path) -> int:
    path = home / "state" / "dream" / "runs.jsonl"
    if not path.is_file():
        return 0
    return sum(1 for line in path.read_text(encoding="utf-8").splitlines() if line.strip())


def compute_maturity_signals(home: Path) -> dict[str, Any]:
    store = SubjectStateStore(home)
    store.ensure_defaults()
    meta = load_subject_meta(home)
    narrative_eligible = _count_narrative_eligible(store)
    evolution_promotes = _count_evolution_promotes(store)
    subject_atoms = _count_subject_atoms(home)
    dream_runs = _count_dream_runs(home)
    manual = bool(meta.get("subject_matured_manual"))
    signals = {
        "narrative_eligible": narrative_eligible,
        "narrative_eligible_met": narrative_eligible >= _NARRATIVE_ELIGIBLE_MIN,
        "evolution_promotes": evolution_promotes,
        "evolution_promotes_met": evolution_promotes >= _EVOLUTION_PROMOTE_MIN,
        "subject_atoms": subject_atoms,
        "subject_atoms_met": subject_atoms >= _ATOM_COUNT_MIN,
        "dream_runs": dream_runs,
        "dream_runs_met": dream_runs >= _DREAM_RUN_MIN,
        "manual": manual,
    }
    auto = any(
        [
            signals["narrative_eligible_met"],
            signals["evolution_promotes_met"],
            signals["subject_atoms_met"] and signals["dream_runs_met"],
        ]
    )
    subject_matured = manual or auto
    return {"subject_matured": subject_matured, "signals": signals}


def refresh_subject_matured(home: Path) -> dict[str, Any]:
    result = compute_maturity_signals(home)
    meta = load_subject_meta(home)
    meta["subject_matured"] = bool(result["subject_matured"])
    meta["maturity_signals"] = result["signals"]
    save_subject_meta(home, meta)
    return result
