"""Confidence scoring + routing decision.

The score is a weighted blend of:
  - mean OCR confidence across all detected lines
  - validation pass rate (1.0 if no review flags, decreases per flag)

This is intentionally simple for Phase 1; Phase 5 will add LLM logprob
contributions and per-field confidences.
"""

from __future__ import annotations

from ocr_sprint.config import get_settings
from ocr_sprint.schemas.document import DocumentStatus
from ocr_sprint.schemas.extraction import ReviewFlag

# Per-flag penalty applied to the validation component of the score.
_FLAG_PENALTY: dict[ReviewFlag, float] = {
    ReviewFlag.LOW_OCR_CONFIDENCE: 0.10,
    ReviewFlag.MISSING_FIELD: 0.20,
    ReviewFlag.INVALID_NRP: 0.10,
    ReviewFlag.UNKNOWN_PANGKAT: 0.05,
    ReviewFlag.PERSONNEL_COUNT_MISMATCH: 0.15,
    ReviewFlag.DATE_PARSE_FAILED: 0.10,
    # Text-based personnel fallback is a recoverable degradation: rank/NRP
    # were extracted via regex from raw OCR rather than from a parsed table
    # grid. Worth flagging for review but not catastrophic.
    ReviewFlag.PERSONNEL_TEXT_FALLBACK: 0.05,
    # An incomplete personnel row (no pangkat AND no nrp) is a strong
    # signal something went wrong. Penalise heavily so the document
    # routes to needs_review even if the rest of the extraction is fine.
    ReviewFlag.INCOMPLETE_PERSONNEL_ROW: 0.15,
}

OCR_WEIGHT = 0.6
VALIDATION_WEIGHT = 0.4


def compute_confidence(
    ocr_confidence: float,
    flags: list[ReviewFlag],
) -> float:
    """Blend OCR confidence with validation penalties into a single 0-1 score."""
    validation_score = 1.0
    for flag in flags:
        validation_score -= _FLAG_PENALTY.get(flag, 0.05)
    validation_score = max(0.0, validation_score)
    blended = OCR_WEIGHT * ocr_confidence + VALIDATION_WEIGHT * validation_score
    return max(0.0, min(1.0, blended))


def route(confidence: float) -> DocumentStatus:
    """Map a final confidence score onto the job's terminal status."""
    s = get_settings()
    if confidence >= s.confidence_auto_approve:
        return DocumentStatus.COMPLETED
    if confidence >= s.confidence_needs_review:
        return DocumentStatus.NEEDS_REVIEW
    return DocumentStatus.NEEDS_REVIEW  # below review threshold also goes to humans
