"""Tests for PriorAuthAI prior authorization validator (chain-based)."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

from claim_validator.constants import Severity
from claim_validator.models.deidentified import (
    DeidentifiedClaim,
    DeidentifiedLineData,
)
from claim_validator.models.results import Finding, ValidatorOutput
from claim_validator.validators.ai.prior_auth import (
    PriorAuthAI,
)

# --- Helpers ---


def _make_claim(
    **overrides: object,
) -> DeidentifiedClaim:
    """Create a de-identified claim for testing."""
    defaults: dict = {
        "billing_provider_npi": "1234567893",
        "patient_age": 45,
        "patient_gender": "M",
        "payer_id": "BCBS01",
        "diagnosis_codes": [
            {"code": "M54.5", "pointer": 1},
        ],
        "lines": [
            DeidentifiedLineData(
                procedure_code="72148",
                diagnosis_pointers=[1],
                charge_amount=800.0,
            ),
        ],
    }
    defaults.update(overrides)
    return DeidentifiedClaim(**defaults)


def _make_mock_chain_result(findings=None):
    """Create a mock chain result."""
    result = MagicMock()
    if findings is None:
        findings = []
    result.to_validator_output.return_value = ValidatorOutput(
        validator_name="PriorAuthAI",
        findings=findings,
    )
    return result


# --- Tests ---


class TestPriorAuthAICleanClaim:
    """Test zero findings when no prior auth needed."""

    @patch("claim_validator.chains.base.invoke_chain_safe")
    def test_no_auth_returns_empty(self, mock_invoke) -> None:
        mock_invoke.return_value = _make_mock_chain_result()
        mock_chain = MagicMock()
        validator = PriorAuthAI(chain=mock_chain)
        result = validator.validate_deidentified(_make_claim())
        assert isinstance(result, ValidatorOutput)
        assert len(result.findings) == 0

    @patch("claim_validator.chains.base.invoke_chain_safe")
    def test_validator_name(self, mock_invoke) -> None:
        mock_invoke.return_value = _make_mock_chain_result()
        mock_chain = MagicMock()
        validator = PriorAuthAI(chain=mock_chain)
        result = validator.validate_deidentified(_make_claim())
        assert result.validator_name == "PriorAuthAI"


class TestPriorAuthAIWithFindings:
    """Test prior auth concerns produce findings."""

    @patch("claim_validator.chains.base.invoke_chain_safe")
    def test_prior_auth_produces_finding(self, mock_invoke) -> None:
        finding = Finding(
            code="AI_PRIOR_AUTH_LIKELY",
            message="MRI typically requires prior authorization",
            severity=Severity.WARNING,
            field_name="procedure_code",
            line_number=1,
            suggestion="Verify prior authorization status with the payer before submission.",
        )
        mock_invoke.return_value = _make_mock_chain_result(findings=[finding])
        mock_chain = MagicMock()
        validator = PriorAuthAI(chain=mock_chain)
        result = validator.validate_deidentified(_make_claim())
        assert len(result.findings) == 1
        f = result.findings[0]
        assert f.code == "AI_PRIOR_AUTH_LIKELY"
        assert f.severity == Severity.WARNING

    @patch("claim_validator.chains.base.invoke_chain_safe")
    def test_multiple_findings(self, mock_invoke) -> None:
        findings = [
            Finding(
                code="AI_PRIOR_AUTH_LIKELY",
                message="Auth A",
                severity=Severity.WARNING,
                field_name="procedure_code",
                line_number=1,
            ),
            Finding(
                code="AI_PRIOR_AUTH_LIKELY",
                message="Auth B",
                severity=Severity.WARNING,
                field_name="procedure_code",
                line_number=2,
            ),
        ]
        mock_invoke.return_value = _make_mock_chain_result(findings=findings)
        mock_chain = MagicMock()
        validator = PriorAuthAI(chain=mock_chain)
        result = validator.validate_deidentified(_make_claim())
        assert len(result.findings) == 2


class TestPriorAuthAIChainFallback:
    """Test chain failure produces empty results."""

    @patch("claim_validator.chains.base.invoke_chain_safe")
    def test_chain_returns_none_fallback(self, mock_invoke) -> None:
        mock_invoke.return_value = None
        mock_chain = MagicMock()
        validator = PriorAuthAI(chain=mock_chain)
        result = validator.validate_deidentified(_make_claim())
        assert len(result.findings) == 0


class TestPriorAuthAINoPHI:
    """Test no PHI in findings."""

    @patch("claim_validator.chains.base.invoke_chain_safe")
    def test_no_phi_in_findings(self, mock_invoke) -> None:
        finding = Finding(
            code="AI_PRIOR_AUTH_LIKELY",
            message="Prior auth required",
            severity=Severity.WARNING,
            field_name="procedure_code",
            line_number=1,
        )
        mock_invoke.return_value = _make_mock_chain_result(findings=[finding])
        mock_chain = MagicMock()
        validator = PriorAuthAI(chain=mock_chain)
        result = validator.validate_deidentified(_make_claim())
        for f in result.findings:
            assert "John" not in f.message
            assert "SSN" not in f.message.upper()
