"""Candidate risk rule discovery from reviewed risk observations."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


@dataclass(frozen=True, slots=True)
class CandidateRiskRule:
    candidate_id: str
    rule_code: str
    title: str
    risk_signal: str
    evidence: list[dict[str, Any]]
    source: str
    confidence_score: float
    status: str = "candidate_review"

    def as_dict(self) -> dict[str, Any]:
        return {
            "candidate_id": self.candidate_id,
            "rule_code": self.rule_code,
            "title": self.title,
            "risk_signal": self.risk_signal,
            "evidence": list(self.evidence),
            "source": self.source,
            "confidence_score": self.confidence_score,
            "status": self.status,
        }


class CandidateRiskRuleDiscovery:
    def discover_from_feedback(
        self,
        observations: list[dict[str, Any]],
        feedback_items: list[dict[str, Any]],
    ) -> list[CandidateRiskRule]:
        observation_by_key = {
            str(item.get("observation_key") or item.get("id") or ""): item
            for item in observations
        }
        candidates: list[CandidateRiskRule] = []
        for feedback in feedback_items:
            source = str(feedback.get("candidate_rule_source") or "").strip()
            decision = str(feedback.get("decision") or feedback.get("feedback_type") or "").strip()
            if source != "risk_observation_feedback" and "candidate" not in decision:
                continue
            observation_key = str(feedback.get("observation_key") or "").strip()
            observation = observation_by_key.get(observation_key, {})
            risk_signal = str(
                feedback.get("risk_signal") or observation.get("risk_signal") or ""
            ).strip()
            if not risk_signal:
                continue
            confidence = _confidence(feedback, observation)
            candidates.append(
                CandidateRiskRule(
                    candidate_id=f"candidate:{observation_key or risk_signal}:{risk_signal}",
                    rule_code=f"candidate.risk.{risk_signal}",
                    title=f"{risk_signal} candidate rule",
                    risk_signal=risk_signal,
                    evidence=_candidate_evidence(observation, feedback),
                    source=source or "risk_observation_feedback",
                    confidence_score=confidence,
                )
            )
        return _dedupe_candidates(candidates)


def _confidence(feedback: dict[str, Any], observation: dict[str, Any]) -> float:
    raw = feedback.get("confidence_score")
    if raw in (None, ""):
        raw = observation.get("confidence_score")
    try:
        return max(0.0, min(1.0, float(raw or 0.55)))
    except (TypeError, ValueError):
        return 0.55


def _candidate_evidence(
    observation: dict[str, Any],
    feedback: dict[str, Any],
) -> list[dict[str, Any]]:
    evidence: list[dict[str, Any]] = []
    for item in observation.get("evidence", []) or []:
        if isinstance(item, dict):
            evidence.append({"source": item.get("source") or "observation", **item})
    evidence.append(
        {
            "source": feedback.get("candidate_rule_source") or "risk_observation_feedback",
            "feedback_type": feedback.get("feedback_type"),
            "action": feedback.get("action"),
            "comment": feedback.get("comment"),
        }
    )
    return evidence


def _dedupe_candidates(candidates: list[CandidateRiskRule]) -> list[CandidateRiskRule]:
    by_code: dict[str, CandidateRiskRule] = {}
    for candidate in candidates:
        current = by_code.get(candidate.rule_code)
        if current is None or candidate.confidence_score > current.confidence_score:
            by_code[candidate.rule_code] = candidate
    return list(by_code.values())
