"""Sacred Boundary #7: Brain self-modification approval gate.

High-impact consolidation stages (schema promotion, pattern evolution,
reconsolidation) require approval above a threshold. Below threshold:
auto-approved. Above: queued for human review via `pulse approve`.
"""
import json
from datetime import datetime, timezone
from pathlib import Path
from pulse.core.paths import get_state_dir
from pulse.core import event_bus
from pulse.core.brain_io import _acquire

# P47 FIX: Moved to state/health/ — compliance_validator deletes unsigned JSON in state/ root
PENDING_FILE = get_state_dir() / "health" / "pending_approvals.json"

# Max items auto-approved per consolidation run, per stage.
# Anything above this threshold is queued for human review.
AUTO_APPROVE_THRESHOLDS = {
    "schema_promotion": 3,
    "promote_to_patterns": 5,
    "pattern_evolution": 2,
    "reconsolidation": 10,
    "goal_generation": 3,
    "abstraction": 3,
    "culture_synthesis": 5,
}


def check_approval(stage: str, items: list) -> tuple[list, list]:
    """Split items into auto-approved and pending-human-approval.

    Returns (approved_items, blocked_items).
    Blocked items are persisted to PENDING_FILE for human review.
    """
    threshold = AUTO_APPROVE_THRESHOLDS.get(stage, 5)
    if len(items) <= threshold:
        return items, []

    sorted_items = sorted(items, key=lambda x: x.get("salience", 0) * x.get("confidence", 0), reverse=True)
    approved = sorted_items[:threshold]
    blocked = sorted_items[threshold:]
    _queue_for_approval(stage, blocked)
    event_bus.publish("approval.needed", "approval_gate", {
        "stage": stage, "auto_approved": len(approved),
        "blocked": len(blocked),
    })
    return approved, blocked


def get_pending() -> list:
    """Return all pending approval items for CLI display."""
    if not PENDING_FILE.exists():
        return []
    try:
        return json.loads(PENDING_FILE.read_text(encoding="utf-8"))
    except Exception:
        return []


def resolve_pending(stage: str, approve: bool) -> int:
    """Approve or reject all pending items for a stage. Returns count resolved."""
    pending = get_pending()
    remaining = [p for p in pending if p.get("stage") != stage]
    resolved = [p for p in pending if p.get("stage") == stage]
    count = sum(len(p.get("items", [])) for p in resolved)

    action = "approved" if approve else "rejected"
    for p in resolved:
        p["resolved"] = action
        p["resolved_at"] = datetime.now(timezone.utc).isoformat()

    _save_pending(remaining)
    event_bus.publish(f"approval.{action}", "approval_gate", {
        "stage": stage, "count": count,
    })
    return count


def _queue_for_approval(stage: str, items: list):
    """Append blocked items to the pending file."""
    pending = get_pending()
    pending.append({
        "stage": stage,
        "queued_at": datetime.now(timezone.utc).isoformat(),
        "item_count": len(items),
        "items": items[:20],  # Cap stored detail to prevent bloat
    })
    _save_pending(pending)


def _save_pending(data: list):
    PENDING_FILE.parent.mkdir(parents=True, exist_ok=True)
    with _acquire(PENDING_FILE):
        PENDING_FILE.write_text(json.dumps(data, indent=2), encoding="utf-8")
