#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""Metrics and alert matching helpers for prediction feedback."""
from __future__ import annotations

import json
from pathlib import Path
from pulse.core.brain_utils import atomic_update_json, load_json_dict

def update_metrics(metrics_file: Path, outcome_type: str, confidence: float, now_iso_fn):
    """Update prediction_metrics.json with outcome classification."""
    def _updater(data):
        if not isinstance(data, dict):
            data = {"total_predictions": 0, "outcomes": {}, "accuracy_by_confidence": {}, "last_updated": ""}
        data["total_predictions"] = data.get("total_predictions", 0) + 1
        outcomes = data.setdefault("outcomes", {})
        outcomes[outcome_type] = outcomes.get(outcome_type, 0) + 1
        if confidence < 0.5:
            bucket = "0.3-0.5"
        elif confidence < 0.7:
            bucket = "0.5-0.7"
        else:
            bucket = "0.7-1.0"
        by_conf = data.setdefault("accuracy_by_confidence", {})
        bucket_data = by_conf.setdefault(bucket, {"correct": 0, "total": 0})
        bucket_data["total"] = bucket_data.get("total", 0) + 1
        if outcome_type in ("true_positive", "true_negative"):
            bucket_data["correct"] = bucket_data.get("correct", 0) + 1
        data["last_updated"] = now_iso_fn()
        return data
    metrics_file.parent.mkdir(parents=True, exist_ok=True)
    atomic_update_json(metrics_file, _updater, default={})


def alert_matches(alert: dict, task_id: str, task_title: str = "") -> bool:
    """Check if a prediction alert matches a task (exact → prefix → title)."""
    # 1. Exact ID match
    if alert.get("task_id") == task_id:
        return True
    # 2. ID prefix match (e.g. oracle IDs with different suffixes)
    alert_id = alert.get("task_id", "")
    if alert_id and task_id and (alert_id.startswith(task_id) or task_id.startswith(alert_id)):
        return True
    # 3. Title-based matching (need a title to compare)
    if not task_title:
        return False
    title_lower = task_title.lower()
    if len(title_lower) < 5:
        return False
    # 3a. Check evidence_chain — oracle stores analyzed task titles here
    for evidence in alert.get("evidence_chain", []):
        if isinstance(evidence, str) and evidence.lower() in title_lower:
            return True
        if isinstance(evidence, str) and title_lower in evidence.lower():
            return True
    # 3b. Check prediction text or alert task_title
    pred_text = alert.get("prediction", "").lower()
    alert_title = alert.get("task_title", "").lower()
    if pred_text and title_lower in pred_text:
        return True
    if alert_title and title_lower in alert_title:
        return True
    return False


def resolve_task_title(task_id: str, state_dir: Path) -> str:
    """Look up a task's title from the task board by its ID."""
    try:
        board = load_json_dict(state_dir / "task_board.json")
        for d in board.get("dispatches", []):
            for t in d.get("tasks", []):
                tid = t.get("task_id") or t.get("id", "")
                if tid == task_id:
                    return t.get("title", "")
    except Exception:
        pass
    return ""
