"""Phase 5F: Structured Dissent — resolve conflicting agent outcomes."""
import json
import uuid
from datetime import datetime, timezone
from pathlib import Path
from pulse.core.paths import get_state_dir
from pulse.core import event_bus

DISSENT_LOG = get_state_dir() / "dissent_log.json"


def _load_dissents() -> dict:
    if not DISSENT_LOG.exists():
        return {"dissents": []}
    try:
        return json.loads(DISSENT_LOG.read_text(encoding="utf-8"))
    except Exception:
        return {"dissents": []}


def _save_dissents(data: dict):
    DISSENT_LOG.parent.mkdir(parents=True, exist_ok=True)
    DISSENT_LOG.write_text(json.dumps(data, indent=2), encoding="utf-8")


def record_dissent(task_id: str, outcomes: list) -> str:
    """
    Record conflicting outcomes from multiple agents on same task.
    outcomes: [{"agent": str, "result": dict, "confidence": float, "reasoning": str}, ...]
    Returns dissent ID.
    """
    if len(outcomes) < 2:
        return ""

    confidences = [o.get("confidence", 0.5) for o in outcomes]
    gap = max(confidences) - min(confidences)

    dissent = {
        "id": f"dissent_{uuid.uuid4().hex[:8]}",
        "task_id": task_id,
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "agents_involved": [o["agent"] for o in outcomes],
        "outcomes": outcomes,
        "confidence_gap": round(gap, 3),
        "resolution_action": "pending",
        "status": "pending"
    }

    data = _load_dissents()
    data["dissents"].append(dissent)
    _save_dissents(data)
    event_bus.publish("dissent.recorded", "dissent", {"dissent_id": dissent["id"], "task_id": task_id, "gap": gap})
    return dissent["id"]


def arbitrate(dissent_id: str) -> dict:
    """
    Confidence-weighted arbitration.
    gap < 0.20 -> escalate to human (too close to call)
    gap >= 0.20 -> select higher confidence
    """
    data = _load_dissents()
    for d in data["dissents"]:
        if d["id"] != dissent_id:
            continue
        if d["status"] != "pending":
            return {"status": d["status"], "resolution": d.get("resolution_action")}

        outcomes = d["outcomes"]
        gap = d["confidence_gap"]

        if gap < 0.20:
            d["resolution_action"] = "escalate_to_human"
            d["status"] = "escalated"
        else:
            winner = max(outcomes, key=lambda o: o.get("confidence", 0))
            d["resolution_action"] = "select_higher_confidence"
            d["final_outcome"] = winner["result"]
            d["status"] = "resolved"
            event_bus.publish("dissent.resolved", "dissent", {
                "dissent_id": dissent_id, "winner": winner["agent"], "confidence": winner["confidence"]
            })

        _save_dissents(data)
        return {"status": d["status"], "resolution": d["resolution_action"]}

    return {"status": "not_found"}


def get_pending_dissents() -> list:
    """Return unresolved dissents for human review."""
    data = _load_dissents()
    return [d for d in data["dissents"] if d["status"] in ("pending", "escalated")]
