"""File-backed run receipt store."""

from __future__ import annotations

import json
from pathlib import Path

from .models import RunRecord, SkillEffectRecord


class RunMemoryStore:
    def __init__(self, root: str | Path) -> None:
        self.root = Path(root)
        self.root.mkdir(parents=True, exist_ok=True)
        self.runs_path = self.root / "runs.jsonl"
        self.effects_path = self.root / "skill-effects.jsonl"

    def append_run_record(self, record: RunRecord) -> None:
        self._append_jsonl(self.runs_path, record.to_dict())

    def update_run_record(self, run_id: str, **updates: object) -> RunRecord | None:
        records = self.list_runs()
        updated: RunRecord | None = None
        for index, record in enumerate(records):
            if record.run_id != run_id:
                continue
            payload = record.to_dict()
            payload.update(updates)
            updated = RunRecord.from_dict(payload)
            records[index] = updated
            break
        if updated is None:
            return None
        self.runs_path.parent.mkdir(parents=True, exist_ok=True)
        self.runs_path.write_text(
            "".join(
                json.dumps(record.to_dict(), ensure_ascii=False, sort_keys=True) + "\n"
                for record in records
            ),
            encoding="utf-8",
        )
        return updated

    def append_skill_effect(self, effect: SkillEffectRecord) -> None:
        self._append_jsonl(self.effects_path, effect.to_dict())

    def update_skill_effects_for_run(self, run_id: str, **updates: object) -> list[SkillEffectRecord]:
        effects = [SkillEffectRecord.from_dict(item) for item in self._read_jsonl(self.effects_path)]
        updated: list[SkillEffectRecord] = []
        for index, effect in enumerate(effects):
            if effect.run_id != run_id:
                continue
            payload = effect.to_dict()
            payload.update(updates)
            next_effect = SkillEffectRecord.from_dict(payload)
            effects[index] = next_effect
            updated.append(next_effect)
        if not updated:
            return []
        self.effects_path.parent.mkdir(parents=True, exist_ok=True)
        self.effects_path.write_text(
            "".join(
                json.dumps(effect.to_dict(), ensure_ascii=False, sort_keys=True) + "\n"
                for effect in effects
            ),
            encoding="utf-8",
        )
        return updated

    def list_runs(self) -> list[RunRecord]:
        return [RunRecord.from_dict(item) for item in self._read_jsonl(self.runs_path)]

    def list_runs_by_skill(self, skill_name: str, version: str | None = None, limit: int | None = None) -> list[RunRecord]:
        results: list[RunRecord] = []
        for record in self.list_runs():
            matched = False
            for receipt in record.activated_skills:
                if receipt.skill_name != skill_name:
                    continue
                if version is not None and receipt.skill_version != version:
                    continue
                matched = True
                break
            if matched:
                results.append(record)
        if limit is not None:
            return results[-limit:]
        return results

    def list_skill_effects(self, skill_name: str, version: str | None = None, limit: int | None = None) -> list[SkillEffectRecord]:
        results: list[SkillEffectRecord] = []
        for payload in self._read_jsonl(self.effects_path):
            effect = SkillEffectRecord.from_dict(payload)
            if effect.skill_name != skill_name:
                continue
            if version is not None and effect.skill_version != version:
                continue
            results.append(effect)
        if limit is not None:
            return results[-limit:]
        return results

    @staticmethod
    def _append_jsonl(path: Path, payload: dict) -> None:
        path.parent.mkdir(parents=True, exist_ok=True)
        with path.open("a", encoding="utf-8") as handle:
            handle.write(json.dumps(payload, ensure_ascii=False, sort_keys=True) + "\n")

    @staticmethod
    def _read_jsonl(path: Path) -> list[dict]:
        if not path.exists():
            return []
        results: list[dict] = []
        for line in path.read_text(encoding="utf-8").splitlines():
            cleaned = line.strip()
            if not cleaned:
                continue
            payload = json.loads(cleaned)
            if isinstance(payload, dict):
                results.append(payload)
        return results
