#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""
Save Knowledge Ops: Refinement, correction, and broadcast operations.

Extracted from pulse_save.py per Law 7 (files <= 300 lines).

Operations:
  - refine_knowledge(): Phase 5.9 reconsolidation (fuzzy-match + replace)
  - flag_incorrect_knowledge(): Fix 9 (dispute + correct)
  - broadcast_critical_failure(): Fix 10 (alert other agents)
"""
import re
import sys
from pathlib import Path


from pulse.core.brain_utils import atomic_update_json, text_similarity, HIPPOCAMPUS_DIR
from .save_writers import _now_iso, LESSONS_FILE, FAILS_FILE

PATTERNS_FILE = HIPPOCAMPUS_DIR / "Patterns" / "auto_patterns.md"
CORRECTIONS_FILE = HIPPOCAMPUS_DIR / "Evidence" / "Decisions" / "corrections.json"
BROADCAST_FILE = HIPPOCAMPUS_DIR / "Evidence" / "Sessions" / "broadcast_alerts.json"
REFINEMENT_LOG = HIPPOCAMPUS_DIR / "Evidence" / "Metrics" / "refinement_log.json"


def broadcast_critical_failure(failure_text: str, agent_name: str) -> bool:
    """Broadcast high-salience failures so other agents see them at boot (Fix 10).

    Writes to broadcast_alerts.json (keeps last 10, auto-prunes).
    Only broadcasts if the failure text contains critical keywords.
    """
    critical_keywords = re.compile(
        r"(?:critical|data loss|security|corruption|regression|crash|breaking|"
        r"destroyed|deleted|wiped|lost|catastrophic)", re.IGNORECASE
    )
    if not critical_keywords.search(failure_text):
        return False

    BROADCAST_FILE.parent.mkdir(parents=True, exist_ok=True)

    def _updater(data):
        if not isinstance(data, dict):
            data = {"alerts": []}
        if "alerts" not in data:
            data["alerts"] = []
        data["alerts"].append({
            "failure": failure_text[:300],
            "agent": agent_name,
            "timestamp": _now_iso(),
            "read_by": [],
        })
        data["alerts"] = data["alerts"][-10:]
        data["last_updated"] = _now_iso()
        return data

    atomic_update_json(BROADCAST_FILE, _updater, default={"alerts": []})
    return True


def refine_knowledge(original_snippet: str, updated_text: str, reason: str,
                     agent_name: str = "unknown") -> dict:
    """Refine an existing lesson/pattern/failure with improved knowledge (Phase 5.9).

    Searches auto_lessons.md, auto_patterns.md, and auto_fails.md for the
    original text using fuzzy matching (60% similarity). If found, replaces
    the description and appends revision metadata.
    """
    result = {"refined": False, "file": "", "original": "", "revision_count": 0}

    if not original_snippet or not updated_text:
        return result

    if len(updated_text.strip()) < 25 or len(updated_text.split()) < 5:
        result["error"] = "Updated text too short (min 25 chars, 5 words)"
        return result

    target_files = [LESSONS_FILE, PATTERNS_FILE, FAILS_FILE]

    for md_file in target_files:
        if not md_file.exists():
            continue
        text = md_file.read_text(encoding="utf-8", errors="replace")
        sections = text.split("\n## ")
        new_sections = [sections[0]]
        found = False

        for section in sections[1:]:
            lines = section.split("\n")
            title = lines[0].strip()
            body = "\n".join(lines[1:]).strip()
            section_text = f"{title} {body}"

            sim = text_similarity(original_snippet.lower(), section_text.lower())
            substring_match = original_snippet.lower() in section_text.lower()

            if (sim >= 0.6 or substring_match) and not found:
                found = True
                result["original"] = title[:100]

                rev_count = body.count("**Revised:**")
                result["revision_count"] = rev_count + 1

                now_date = _now_iso()[:10]
                if f"**Revised:** {now_date}" in body and agent_name in body:
                    result["error"] = "Already refined today by this agent"
                    new_sections.append(section)
                    continue

                meta_lines = []
                for line in lines[1:]:
                    if line.startswith("**Source:") or line.startswith("**Revised:") or \
                       line.startswith("**Revision Count:") or line.strip() == "---":
                        meta_lines.append(line)

                new_title = updated_text[:80]
                new_section_lines = [new_title, ""]
                new_section_lines.append(updated_text)
                new_section_lines.append("")

                for ml in meta_lines:
                    if ml.strip() == "---":
                        continue
                    if not ml.startswith("**Revision Count:"):
                        new_section_lines.append(ml)

                new_section_lines.append(
                    f"**Revised:** {_now_iso()[:10]} by {agent_name} | "
                    f"**Previous:** \"{title[:60]}\" | **Reason:** \"{reason[:100]}\""
                )
                new_section_lines.append(f"**Revision Count:** {rev_count + 1}")
                new_section_lines.append("")
                new_section_lines.append("---")

                new_sections.append("\n".join(new_section_lines))
                result["refined"] = True
                result["file"] = md_file.name
            else:
                new_sections.append(section)

        if found:
            md_file.write_text("\n## ".join(new_sections), encoding="utf-8")

            REFINEMENT_LOG.parent.mkdir(parents=True, exist_ok=True)

            def _updater(data):
                if not isinstance(data, dict):
                    data = {"refinements": [], "total": 0}
                if "refinements" not in data:
                    data["refinements"] = []
                data["refinements"].append({
                    "original": result["original"][:100],
                    "updated": updated_text[:100],
                    "reason": reason[:100],
                    "agent": agent_name,
                    "file": md_file.name,
                    "revision_number": result["revision_count"],
                    "timestamp": _now_iso(),
                })
                data["refinements"] = data["refinements"][-200:]
                data["total"] = data.get("total", 0) + 1
                return data

            atomic_update_json(REFINEMENT_LOG, _updater, default={"refinements": [], "total": 0})
            break

    return result


def flag_incorrect_knowledge(query: str, correction: str, agent_name: str = "unknown") -> dict:
    """Flag a lesson/failure as incorrect and log the correction (Fix 9).

    Searches auto_lessons.md and auto_fails.md for matching text,
    appends [DISPUTED] marker, and logs to corrections.json.
    """
    result = {"flagged": False, "file": "", "correction_logged": False}

    for md_file in [LESSONS_FILE, FAILS_FILE]:
        if not md_file.exists():
            continue
        text = md_file.read_text(encoding="utf-8", errors="replace")
        query_lower = query.lower()

        sections = text.split("\n## ")
        new_sections = [sections[0]]
        found = False

        for section in sections[1:]:
            title = section.split("\n")[0].strip().lower()
            body_lower = section.lower()
            if query_lower in title or query_lower in body_lower[:200]:
                if "[DISPUTED]" not in section:
                    section = section.split("\n")[0] + " [DISPUTED]\n" + "\n".join(section.split("\n")[1:])
                    section += f"\n> **DISPUTED** by {agent_name}: {correction}\n"
                    found = True
            new_sections.append(section)

        if found:
            md_file.write_text("\n## ".join(new_sections), encoding="utf-8")
            result["flagged"] = True
            result["file"] = md_file.name
            break

    CORRECTIONS_FILE.parent.mkdir(parents=True, exist_ok=True)

    def _updater(data):
        if not isinstance(data, dict):
            data = {"corrections": []}
        if "corrections" not in data:
            data["corrections"] = []
        data["corrections"].append({
            "query": query,
            "correction": correction,
            "flagged_by": agent_name,
            "timestamp": _now_iso(),
            "source_file": result.get("file", ""),
        })
        data["corrections"] = data["corrections"][-100:]
        return data

    atomic_update_json(CORRECTIONS_FILE, _updater, default={"corrections": []})
    result["correction_logged"] = True

    return result
