"""Rejected candidate storage for audit, learning, and debugging.

Stores candidates rejected during evidence verification with structured reason codes.
Currently in-memory; designed for future persistence to v3_rejected_candidates table.
"""

from __future__ import annotations

from collections import defaultdict

from services.intelligence_pipeline_v3.verification.models import (
    RejectedCandidate,
    RejectionReason,
)


class RejectedCandidateStore:
    """In-memory store for rejected candidates, queryable by pipeline run and reason.

    Designed to be replaced with a database-backed implementation once
    the v3_rejected_candidates table is deployed. The interface is stable.
    """

    def __init__(self) -> None:
        self._by_run: dict[str, list[RejectedCandidate]] = defaultdict(list)
        self._by_reason: dict[RejectionReason, list[RejectedCandidate]] = defaultdict(list)
        self._all: list[RejectedCandidate] = []

    def store(self, rejected: RejectedCandidate, run_id: str = "default") -> None:
        """Store a rejected candidate.

        Args:
            rejected: The rejected candidate to store.
            run_id: Pipeline run identifier for grouping.
        """
        self._all.append(rejected)
        self._by_run[run_id].append(rejected)
        self._by_reason[rejected.rejection_reason].append(rejected)

    def store_batch(self, rejected_list: list[RejectedCandidate], run_id: str = "default") -> None:
        """Store multiple rejected candidates in one call.

        Args:
            rejected_list: List of rejected candidates to store.
            run_id: Pipeline run identifier for grouping.
        """
        for r in rejected_list:
            self.store(r, run_id)

    def get_by_pipeline_run(self, run_id: str) -> list[RejectedCandidate]:
        """Retrieve all rejected candidates for a given pipeline run.

        Args:
            run_id: Pipeline run identifier.

        Returns:
            List of rejected candidates for that run (empty if none).
        """
        return list(self._by_run.get(run_id, []))

    def get_by_reason(self, reason: RejectionReason) -> list[RejectedCandidate]:
        """Retrieve all rejected candidates with a specific rejection reason.

        Args:
            reason: The rejection reason code to filter by.

        Returns:
            List of rejected candidates with that reason (empty if none).
        """
        return list(self._by_reason.get(reason, []))

    def get_all(self) -> list[RejectedCandidate]:
        """Retrieve all stored rejected candidates.

        Returns:
            List of all rejected candidates.
        """
        return list(self._all)

    def count(self) -> int:
        """Total number of rejected candidates stored."""
        return len(self._all)

    def count_by_reason(self) -> dict[str, int]:
        """Count of rejected candidates grouped by reason code.

        Returns:
            Mapping from reason code string to count.
        """
        return {reason.value: len(items) for reason, items in self._by_reason.items()}

    def clear(self) -> None:
        """Remove all stored rejected candidates."""
        self._by_run.clear()
        self._by_reason.clear()
        self._all.clear()
