"""Pending failures — file-based queue for within-session real-time failure learning.

Failures are written to state/pending_failures.jsonl (append-only, no SQLite lock).
The brain hook reads this file before every action for <1s failure availability.
The bridge daemon flushes entries to SQLite on its next cycle.
"""
import json
import time
from pathlib import Path
from pulse.core.paths import get_state_dir
from pulse.core.brain_utils import _make_fingerprint

PENDING_FILE = get_state_dir() / "pending_failures.jsonl"


def write_pending_failure(content: str, agent: str = "unknown", domain: str = "general"):
    """Append a failure to the pending file (no DB lock, <1ms)."""
    if not content or len(content.strip()) < 10:
        return
    entry = {
        "content": content.strip()[:500],
        "agent": agent,
        "domain": domain,
        "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime()),
        "fingerprint": _make_fingerprint(content),
    }
    try:
        PENDING_FILE.parent.mkdir(parents=True, exist_ok=True)
        with open(PENDING_FILE, "a", encoding="utf-8") as f:
            f.write(json.dumps(entry, ensure_ascii=False) + "\n")
    except Exception:
        pass


def read_pending_failures(max_items: int = 20) -> list:
    """Read recent pending failures (for brain hook injection)."""
    if not PENDING_FILE.exists():
        return []
    try:
        lines = PENDING_FILE.read_text(encoding="utf-8", errors="replace").strip().splitlines()
        results = []
        seen = set()
        for line in reversed(lines[-max_items * 2:]):
            try:
                entry = json.loads(line)
                fp = entry.get("fingerprint", "")
                if fp and fp in seen:
                    continue
                seen.add(fp)
                results.append(entry)
                if len(results) >= max_items:
                    break
            except (json.JSONDecodeError, KeyError):
                continue
        return results
    except Exception:
        return []


def flush_to_sqlite() -> int:
    """Move pending failures into SQLite and truncate the file. Returns count flushed."""
    entries = read_pending_failures(max_items=500)
    if not entries:
        return 0
    flushed = 0
    try:
        from pulse.core.brain_db import insert_knowledge
        for entry in entries:
            result = insert_knowledge("failures", {
                "content": entry["content"],
                "agent": entry.get("agent", "unknown"),
                "domain": entry.get("domain", "general"),
                "timestamp": entry.get("timestamp", ""),
                "confidence": 0.55,
                "salience": 1.5,
                "source_type": "OBSERVED",
                "type": "failure",
            })
            if result and result != "bcm_shed":
                flushed += 1
    except Exception:
        pass
    # Truncate file after successful flush
    if flushed > 0:
        try:
            PENDING_FILE.write_text("", encoding="utf-8")
        except Exception:
            pass
    return flushed
