# recoil/pipeline/lib/bible_resolver.py
"""Bible priority cascade (Phase 1). Per spec D5:
pipeline_client → pipeline_global → narrative → engine_store
"""

from __future__ import annotations

import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any

from recoil.core.paths import projects_root, ProjectPaths


@dataclass
class BibleSnapshot:
    content: dict[str, Any]
    source: str  # "pipeline_client" | "pipeline_global" | "narrative" | "engine_store"
    run_id: str | None = None


_RUN_CACHE: dict[tuple[str, str], BibleSnapshot] = {}


def _project_root(project: str) -> Path:
    return projects_root() / project


def resolve_bible(
    project: str,
    *,
    run_id: str | None = None,
    phase: str | None = None,
    force: bool = False,
) -> BibleSnapshot:
    cache_key = (project, run_id or "")
    if run_id and not force and cache_key in _RUN_CACHE:
        return _RUN_CACHE[cache_key]

    proj = _project_root(project)
    state = ProjectPaths.from_root(proj).visual_state_dir

    candidates = [
        ("pipeline_client", state / "client_bible.json"),
        ("pipeline_global", state / "global_bible.json"),
        ("narrative", proj / "bible.json"),
        ("engine_store", state / "bibles.jsonl"),
    ]

    snapshot: BibleSnapshot | None = None
    for source_name, path in candidates:
        if not path.exists():
            continue
        try:
            if source_name == "engine_store":
                # JSONL file — parse line by line, take the last valid record.
                last_valid: Any = None
                with path.open() as f:
                    for line in f:
                        line = line.strip()
                        if not line:
                            continue
                        try:
                            last_valid = json.loads(line)
                        except json.JSONDecodeError:
                            continue
                if last_valid is not None:
                    # Record shape is {"id": ..., "source": ..., "content": ...}
                    if isinstance(last_valid, dict):
                        content = last_valid.get("content", last_valid)
                    else:
                        content = {}
                    snapshot = BibleSnapshot(content=content, source=source_name, run_id=run_id)
                    break
            else:
                content = json.loads(path.read_text())
                snapshot = BibleSnapshot(content=content, source=source_name, run_id=run_id)
                break
        except json.JSONDecodeError:
            continue

    if snapshot is None:
        snapshot = BibleSnapshot(content={}, source="engine_store", run_id=run_id)

    if run_id:
        _RUN_CACHE[cache_key] = snapshot
    return snapshot


def capture_for_run(run_id: str, project: str) -> BibleSnapshot:
    snap = resolve_bible(project, run_id=run_id, force=True)
    _RUN_CACHE[(project, run_id)] = snap

    # Append to bibles.jsonl for durable history
    visual_dir = ProjectPaths.from_root(_project_root(project)).visual_state_dir
    visual_dir.mkdir(parents=True, exist_ok=True)
    bibles_log = visual_dir / "bibles.jsonl"
    record = {
        "id": f"bib_{project}_{run_id}",
        "source": snap.source,
        "content": snap.content,
    }
    with bibles_log.open("a") as f:
        f.write(json.dumps(record) + "\n")
    return snap
