"""Tests for ModifierCompatibilityValidator — modifier conflict detection."""

from __future__ import annotations

from claim_validator.constants import Severity
from claim_validator.models.results import ValidatorOutput
from claim_validator.validators.rule_based.modifier_compatibility import (
    ModifierCompatibilityValidator,
)
from tests.conftest import build_claim_unchecked


def _valid_claim_dict() -> dict:
    """Minimal claim dict with valid modifiers."""
    return {
        "billing_provider_npi": "1234567893",
        "subscriber_id": "XYZ123456",
        "patient_first_name": "Jane",
        "patient_last_name": "Doe",
        "patient_dob": "1990-01-15",
        "patient_gender": "F",
        "payer_id": "BCBS001",
        "diagnosis_codes": [{"code": "J06.9", "pointer": 1}],
        "lines": [
            {
                "procedure_code": "99213",
                "modifiers": ["25"],
                "diagnosis_pointers": [1],
                "charge_amount": 150.00,
                "service_date_from": "2026-01-15",
            },
        ],
    }


class TestModifierCompatibilityValid:
    """Tests for valid modifier combinations producing zero findings."""

    def setup_method(self) -> None:
        self.validator = ModifierCompatibilityValidator()

    def test_valid_modifiers_no_findings(self) -> None:
        claim = build_claim_unchecked(**_valid_claim_dict())
        result = self.validator.validate(claim)
        assert result.findings == []

    def test_validator_name(self) -> None:
        assert self.validator.name == "ModifierCompatibilityValidator"

    def test_returns_validator_output(self) -> None:
        claim = build_claim_unchecked(**_valid_claim_dict())
        result = self.validator.validate(claim)
        assert isinstance(result, ValidatorOutput)
        assert result.validator_name == "ModifierCompatibilityValidator"

    def test_no_modifiers_no_findings(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = []
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        assert result.findings == []

    def test_x_modifier_alone_is_valid(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["XE"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        assert result.findings == []

    def test_modifier_59_alone_is_valid(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["59"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        assert result.findings == []


class TestModifier59WithXModifier:
    """Rule 1: Modifier 59 + X-modifier conflict."""

    def setup_method(self) -> None:
        self.validator = ModifierCompatibilityValidator()

    def test_59_with_xe_flags_error(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["59", "XE"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "MODIFIER_59_WITH_X_MODIFIER"]
        assert len(findings) == 1
        assert findings[0].severity == Severity.ERROR
        assert findings[0].field_name == "modifiers"
        assert findings[0].line_number == 1

    def test_59_with_xs_flags_error(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["59", "XS"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "MODIFIER_59_WITH_X_MODIFIER"]
        assert len(findings) == 1

    def test_59_with_xp_flags_error(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["59", "XP"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "MODIFIER_59_WITH_X_MODIFIER"]
        assert len(findings) == 1

    def test_59_with_xu_flags_error(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["59", "XU"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "MODIFIER_59_WITH_X_MODIFIER"]
        assert len(findings) == 1

    def test_suggestion_present(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["59", "XE"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "MODIFIER_59_WITH_X_MODIFIER"]
        assert "X-modifier" in findings[0].suggestion


class TestBilateralModifierDuplicate:
    """Rule 2: Bilateral modifier 50 duplicates."""

    def setup_method(self) -> None:
        self.validator = ModifierCompatibilityValidator()

    def test_bilateral_with_separate_line_flags_warning(self) -> None:
        data = _valid_claim_dict()
        data["lines"] = [
            {
                "procedure_code": "27447",
                "modifiers": ["50"],
                "diagnosis_pointers": [1],
                "charge_amount": 5000.00,
                "service_date_from": "2026-01-15",
            },
            {
                "procedure_code": "27447",
                "modifiers": [],
                "diagnosis_pointers": [1],
                "charge_amount": 5000.00,
                "service_date_from": "2026-01-15",
            },
        ]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "BILATERAL_MODIFIER_DUPLICATE"]
        assert len(findings) == 1
        assert findings[0].severity == Severity.WARNING
        assert findings[0].line_number == 1

    def test_bilateral_alone_no_duplicate_warning(self) -> None:
        data = _valid_claim_dict()
        data["lines"] = [
            {
                "procedure_code": "27447",
                "modifiers": ["50"],
                "diagnosis_pointers": [1],
                "charge_amount": 5000.00,
                "service_date_from": "2026-01-15",
            },
        ]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "BILATERAL_MODIFIER_DUPLICATE"]
        assert findings == []

    def test_bilateral_different_dates_no_warning(self) -> None:
        data = _valid_claim_dict()
        data["lines"] = [
            {
                "procedure_code": "27447",
                "modifiers": ["50"],
                "diagnosis_pointers": [1],
                "charge_amount": 5000.00,
                "service_date_from": "2026-01-15",
            },
            {
                "procedure_code": "27447",
                "modifiers": [],
                "diagnosis_pointers": [1],
                "charge_amount": 5000.00,
                "service_date_from": "2026-01-20",
            },
        ]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "BILATERAL_MODIFIER_DUPLICATE"]
        assert findings == []

    def test_bilateral_different_procedures_no_warning(self) -> None:
        data = _valid_claim_dict()
        data["lines"] = [
            {
                "procedure_code": "27447",
                "modifiers": ["50"],
                "diagnosis_pointers": [1],
                "charge_amount": 5000.00,
                "service_date_from": "2026-01-15",
            },
            {
                "procedure_code": "29881",
                "modifiers": [],
                "diagnosis_pointers": [1],
                "charge_amount": 3000.00,
                "service_date_from": "2026-01-15",
            },
        ]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "BILATERAL_MODIFIER_DUPLICATE"]
        assert findings == []


class TestConflictingGlobalModifiers:
    """Rule 3: Modifiers 54 and 55 conflict."""

    def setup_method(self) -> None:
        self.validator = ModifierCompatibilityValidator()

    def test_54_and_55_flags_error(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["54", "55"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "CONFLICTING_GLOBAL_MODIFIERS"]
        assert len(findings) == 1
        assert findings[0].severity == Severity.ERROR
        assert findings[0].line_number == 1

    def test_54_alone_is_valid(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["54"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "CONFLICTING_GLOBAL_MODIFIERS"]
        assert findings == []

    def test_55_alone_is_valid(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["55"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "CONFLICTING_GLOBAL_MODIFIERS"]
        assert findings == []


class TestTCProfessionalConflict:
    """Rule 4: TC and 26 conflict."""

    def setup_method(self) -> None:
        self.validator = ModifierCompatibilityValidator()

    def test_tc_and_26_flags_error(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["TC", "26"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "TC_PROFESSIONAL_CONFLICT"]
        assert len(findings) == 1
        assert findings[0].severity == Severity.ERROR
        assert findings[0].line_number == 1

    def test_tc_alone_is_valid(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["TC"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "TC_PROFESSIONAL_CONFLICT"]
        assert findings == []

    def test_26_alone_is_valid(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["26"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "TC_PROFESSIONAL_CONFLICT"]
        assert findings == []


class TestDuplicateModifier:
    """Rule 5: Duplicate modifiers on a line."""

    def setup_method(self) -> None:
        self.validator = ModifierCompatibilityValidator()

    def test_duplicate_modifier_flags_warning(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["25", "25"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "DUPLICATE_MODIFIER"]
        assert len(findings) == 1
        assert findings[0].severity == Severity.WARNING
        assert "25" in findings[0].message

    def test_no_duplicate_no_warning(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["25", "59"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "DUPLICATE_MODIFIER"]
        assert findings == []

    def test_triple_duplicate_flags_one_warning(self) -> None:
        data = _valid_claim_dict()
        data["lines"][0]["modifiers"] = ["TC", "TC", "TC"]
        claim = build_claim_unchecked(**data)
        result = self.validator.validate(claim)
        findings = [f for f in result.findings if f.code == "DUPLICATE_MODIFIER"]
        assert len(findings) == 1
        assert "TC" in findings[0].message
