"""Unit tests for extended HealthStatus model (Story 2.4).

Tests new fields added for AMQP/HTTP health tracking.
"""

from __future__ import annotations

from datetime import UTC, datetime

import pytest
from pydantic import ValidationError

from rabbitmq_mcp_connection.schemas.connection import HealthStatus


def test_health_status_basic_fields():
    """Test basic HealthStatus model fields."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=10.5,
        last_check=now,
        error_message=None,
    )

    assert status.is_connected is True
    assert status.broker_available is True
    assert status.latency_ms == 10.5
    assert status.last_check == now
    assert status.error_message is None


def test_health_status_new_fields():
    """Test new fields added in Story 2.4 (AC #7)."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=15.0,
        last_check=now,
        amqp_connected=True,
        http_connected=True,
        consecutive_failures=0,
    )

    assert status.amqp_connected is True
    assert status.http_connected is True
    assert status.consecutive_failures == 0


def test_health_status_default_new_fields():
    """Test new fields have sensible defaults."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=10.0,
        last_check=now,
    )

    # New fields should default to False/0
    assert status.amqp_connected is False
    assert status.http_connected is False
    assert status.consecutive_failures == 0


def test_is_healthy_both_connected():
    """Test is_healthy returns True when both AMQP and HTTP connected (AC #7)."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=10.0,
        last_check=now,
        amqp_connected=True,
        http_connected=True,
        consecutive_failures=0,
    )

    assert status.is_healthy is True


def test_is_healthy_amqp_disconnected():
    """Test is_healthy returns False when AMQP disconnected."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=False,
        broker_available=False,
        latency_ms=10.0,
        last_check=now,
        amqp_connected=False,
        http_connected=True,
        consecutive_failures=1,
    )

    assert status.is_healthy is False


def test_is_healthy_http_disconnected():
    """Test is_healthy returns False when HTTP disconnected."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=10.0,
        last_check=now,
        amqp_connected=True,
        http_connected=False,
        consecutive_failures=1,
    )

    assert status.is_healthy is False


def test_is_healthy_both_disconnected():
    """Test is_healthy returns False when both disconnected."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=False,
        broker_available=False,
        latency_ms=10.0,
        last_check=now,
        amqp_connected=False,
        http_connected=False,
        consecutive_failures=3,
    )

    assert status.is_healthy is False


def test_health_status_with_error_message():
    """Test HealthStatus with error message."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=False,
        broker_available=False,
        latency_ms=1000.0,
        last_check=now,
        error_message="Connection timeout",
        amqp_connected=False,
        http_connected=False,
        consecutive_failures=2,
    )

    assert status.error_message == "Connection timeout"
    assert status.is_healthy is False


def test_health_status_consecutive_failures():
    """Test consecutive_failures tracking."""
    now = datetime.now(UTC)

    # No failures
    status1 = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=10.0,
        last_check=now,
        amqp_connected=True,
        http_connected=True,
        consecutive_failures=0,
    )
    assert status1.consecutive_failures == 0

    # 3 failures (threshold)
    status2 = HealthStatus(
        is_connected=False,
        broker_available=False,
        latency_ms=10.0,
        last_check=now,
        amqp_connected=False,
        http_connected=False,
        consecutive_failures=3,
    )
    assert status2.consecutive_failures == 3


def test_health_status_model_dump():
    """Test HealthStatus serialization to dict."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=12.34,
        last_check=now,
        amqp_connected=True,
        http_connected=True,
        consecutive_failures=0,
    )

    data = status.model_dump()

    assert data["is_connected"] is True
    assert data["broker_available"] is True
    assert data["latency_ms"] == 12.34
    assert data["amqp_connected"] is True
    assert data["http_connected"] is True
    assert data["consecutive_failures"] == 0
    assert data["is_healthy"] is True


def test_health_status_model_dump_json():
    """Test HealthStatus serialization to JSON."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=12.34,
        last_check=now,
        amqp_connected=True,
        http_connected=False,
        consecutive_failures=1,
    )

    json_str = status.model_dump_json()

    assert isinstance(json_str, str)
    assert "amqp_connected" in json_str
    assert "http_connected" in json_str
    assert "consecutive_failures" in json_str


def test_health_status_validation_missing_required():
    """Test HealthStatus validation fails with missing required fields."""
    with pytest.raises(ValidationError):
        HealthStatus(
            # Missing required fields
            latency_ms=10.0,
        )


def test_health_status_validation_invalid_types():
    """Test HealthStatus validation with invalid types."""
    now = datetime.now(UTC)

    # Pydantic v2 coerces many values, so test truly invalid type
    with pytest.raises(ValidationError):
        HealthStatus(
            is_connected=True,
            broker_available=True,
            latency_ms="not_a_number",  # Should be float
            last_check=now,
        )


def test_health_status_backward_compatibility():
    """Test backward compatibility with existing code not using new fields."""
    now = datetime.now(UTC)

    # Old code only sets original fields
    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=10.0,
        last_check=now,
    )

    # Should work without errors
    assert status.is_connected is True
    assert status.broker_available is True
    # New fields have defaults
    assert status.amqp_connected is False
    assert status.http_connected is False
    assert status.consecutive_failures == 0


def test_health_status_high_latency():
    """Test HealthStatus with high latency."""
    now = datetime.now(UTC)

    status = HealthStatus(
        is_connected=True,
        broker_available=True,
        latency_ms=950.0,  # Close to 1 second timeout
        last_check=now,
        amqp_connected=True,
        http_connected=True,
    )

    assert status.latency_ms == 950.0
    assert status.is_healthy is True
