"""
Document Classifier

Business logic for classifying documents based on extracted fields.
Separates classification logic from inference pipeline.
"""
from __future__ import annotations

from dataclasses import dataclass

from backend.domain.utils import has_value


@dataclass(frozen=True)
class ClassificationResult:
    """
    Immutable result of document classification.

    Attributes:
        document_type: Either "invoice" or "letter"
        confidence: Confidence score between 0.0 and 1.0
        reason: Human-readable explanation of classification
    """

    document_type: str
    confidence: float
    reason: str


class DocumentClassifier:
    """
    Classifies documents as invoice or letter based on extracted fields.

    Classification Rules:
    1. If payment_line is present -> invoice (high confidence)
    2. If 2+ invoice indicators present -> invoice (medium confidence)
    3. If 1 invoice indicator present -> invoice (lower confidence)
    4. Otherwise -> letter

    Invoice indicator fields:
    - payment_line (strongest indicator)
    - OCR
    - Amount
    - Bankgiro
    - Plusgiro
    - InvoiceNumber
    """

    INVOICE_INDICATOR_FIELDS: frozenset[str] = frozenset(
        {
            "payment_line",
            "OCR",
            "Amount",
            "Bankgiro",
            "Plusgiro",
            "InvoiceNumber",
        }
    )

    def classify(self, fields: dict[str, str | None]) -> ClassificationResult:
        """
        Classify document type based on extracted fields.

        Args:
            fields: Dictionary of field names to extracted values.
                    Empty strings or whitespace-only strings are treated as missing.

        Returns:
            Immutable ClassificationResult with type, confidence, and reason.
        """
        # Rule 1: payment_line is the strongest indicator
        if has_value(fields.get("payment_line")):
            return ClassificationResult(
                document_type="invoice",
                confidence=0.95,
                reason="payment_line detected",
            )

        # Count present invoice indicators (excluding payment_line already checked)
        present_indicators = [
            field
            for field in self.INVOICE_INDICATOR_FIELDS
            if field != "payment_line" and has_value(fields.get(field))
        ]
        indicator_count = len(present_indicators)

        # Rule 2: Multiple indicators -> invoice with medium-high confidence
        if indicator_count >= 2:
            return ClassificationResult(
                document_type="invoice",
                confidence=0.8,
                reason=f"{indicator_count} invoice indicators present: {', '.join(present_indicators)}",
            )

        # Rule 3: Single indicator -> invoice with lower confidence
        if indicator_count == 1:
            return ClassificationResult(
                document_type="invoice",
                confidence=0.6,
                reason=f"1 invoice indicator present: {present_indicators[0]}",
            )

        # Rule 4: No indicators -> letter
        return ClassificationResult(
            document_type="letter",
            confidence=0.7,
            reason="no invoice indicators found",
        )
