"""Tests for sre_beacon.models."""

from datetime import datetime, timedelta

import pytest

from sre_beacon.models import (
    AlertAuditReport,
    AlertIssue,
    AlertIssueSeverity,
    AvailabilityResult,
    Incident,
    IncidentSeverity,
    MaturityDimension,
    MaturityLevel,
    MaturityReport,
    SLIType,
    SLODefinition,
    SLOResult,
    Severity,
    ToilFrequency,
)


class TestEnums:
    def test_severity_values(self):
        assert Severity.CRITICAL.value == "CRITICAL"
        assert Severity.INFO.value == "INFO"

    def test_sli_types(self):
        assert SLIType.AVAILABILITY.value == "availability"
        assert SLIType.LATENCY.value == "latency"
        assert SLIType.ERROR_RATE.value == "error_rate"

    def test_incident_severity(self):
        assert IncidentSeverity.P1.value == "P1"
        assert IncidentSeverity.P4.value == "P4"

    def test_toil_frequency(self):
        assert ToilFrequency.DAILY.value == "daily"
        assert ToilFrequency.QUARTERLY.value == "quarterly"


class TestSLOResult:
    def test_compliant_availability(self, sample_slo_definition):
        result = SLOResult(slo=sample_slo_definition, actual=99.95)
        assert result.compliant is True
        assert result.error_budget_remaining_pct > 0

    def test_non_compliant_availability(self, sample_slo_definition):
        result = SLOResult(slo=sample_slo_definition, actual=99.8)
        assert result.compliant is False

    def test_error_rate_compliant(self):
        slo = SLODefinition(name="Err", service="svc", sli_type=SLIType.ERROR_RATE, target=99.5)
        result = SLOResult(slo=slo, actual=0.3)  # 0.3% error rate < 0.5% budget
        assert result.compliant is True

    def test_error_rate_non_compliant(self):
        slo = SLODefinition(name="Err", service="svc", sli_type=SLIType.ERROR_RATE, target=99.5)
        result = SLOResult(slo=slo, actual=0.8)  # 0.8% > 0.5% budget
        assert result.compliant is False

    def test_error_budget_total_minutes(self, sample_slo_definition):
        result = SLOResult(slo=sample_slo_definition, actual=99.95)
        # 30 days × 24h × 60m = 43200 min; 0.1% budget = 43.2 min
        assert abs(result.error_budget_total_minutes - 43.2) < 0.01


class TestIncident:
    def test_ttr(self):
        det = datetime(2025, 1, 1, 0, 0)
        inc = Incident(id="1", title="t", severity=IncidentSeverity.P1, service="s",
                       detected_at=det, resolved_at=det + timedelta(minutes=60))
        assert inc.ttr == timedelta(minutes=60)

    def test_tta(self):
        det = datetime(2025, 1, 1, 0, 0)
        inc = Incident(id="1", title="t", severity=IncidentSeverity.P1, service="s",
                       detected_at=det, acknowledged_at=det + timedelta(minutes=5))
        assert inc.tta == timedelta(minutes=5)

    def test_ttr_none_when_unresolved(self):
        inc = Incident(id="1", title="t", severity=IncidentSeverity.P1, service="s",
                       detected_at=datetime.now())
        assert inc.ttr is None


class TestAlertAuditReport:
    def test_score_perfect(self):
        report = AlertAuditReport(total_rules=5, issues=[])
        assert report.score == 100
        assert report.grade == "A+"

    def test_score_with_issues(self):
        issues = [
            AlertIssue(rule_id="X", severity=AlertIssueSeverity.CRITICAL,
                       message="m", alert_name="a"),
            AlertIssue(rule_id="X", severity=AlertIssueSeverity.HIGH,
                       message="m", alert_name="a"),
        ]
        report = AlertAuditReport(total_rules=5, issues=issues)
        assert report.score < 100
        assert report.critical_count == 1
        assert report.high_count == 1

    def test_grade_f(self):
        issues = [AlertIssue(rule_id="X", severity=AlertIssueSeverity.CRITICAL,
                             message="m", alert_name="a")] * 20
        report = AlertAuditReport(total_rules=2, issues=issues)
        assert report.grade == "F"


class TestMaturityDimension:
    def test_level_initial(self):
        dim = MaturityDimension(name="Test", score=0.5)
        assert dim.level == MaturityLevel.INITIAL

    def test_level_optimizing(self):
        dim = MaturityDimension(name="Test", score=4.5)
        assert dim.level == MaturityLevel.OPTIMIZING


class TestMaturityReport:
    def test_overall_score(self):
        dims = [
            MaturityDimension(name="A", score=3.0),
            MaturityDimension(name="B", score=5.0),
        ]
        report = MaturityReport(dimensions=dims)
        assert report.overall_score == 4.0

    def test_weakest_strongest(self):
        dims = [
            MaturityDimension(name="Weak", score=1.0),
            MaturityDimension(name="Strong", score=5.0),
        ]
        report = MaturityReport(dimensions=dims)
        assert report.weakest_dimension.name == "Weak"
        assert report.strongest_dimension.name == "Strong"

    def test_empty(self):
        report = MaturityReport()
        assert report.overall_score == 0.0
        assert report.weakest_dimension is None
