"""
Copyright (C) 2025 Luciano Guerche

This file is part of rabbitmq-mcp-server.

rabbitmq-mcp-server is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

rabbitmq-mcp-server is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with rabbitmq-mcp-server. If not, see <https://www.gnu.org/licenses/>.
"""

"""Unit tests for ReconnectionState schema."""

from datetime import UTC, datetime, timezone

import pytest
from pydantic import ValidationError

from rabbitmq_mcp_connection.schemas.reconnect import ReconnectionState


class TestReconnectionState:
    """Test suite for ReconnectionState model."""

    def test_create_with_all_fields(self) -> None:
        """Test creating ReconnectionState with all fields."""
        now = datetime.now(UTC)
        state = ReconnectionState(
            state="reconnecting",
            attempt=5,
            next_attempt_in_seconds=32,
            total_downtime_seconds=125.5,
            last_reconnect_timestamp=now,
        )

        assert state.state == "reconnecting"
        assert state.attempt == 5
        assert state.next_attempt_in_seconds == 32
        assert state.total_downtime_seconds == 125.5
        assert state.last_reconnect_timestamp == now

    def test_create_with_required_fields_only(self) -> None:
        """Test creating ReconnectionState with only required fields."""
        state = ReconnectionState(state="connected")

        assert state.state == "connected"
        assert state.attempt == 0
        assert state.next_attempt_in_seconds is None
        assert state.total_downtime_seconds == 0.0
        assert state.last_reconnect_timestamp is None

    def test_state_field_required(self) -> None:
        """Test that state field is required."""
        with pytest.raises(ValidationError) as exc_info:
            ReconnectionState()

        assert "state" in str(exc_info.value)

    def test_attempt_must_be_non_negative(self) -> None:
        """Test that attempt must be >= 0."""
        with pytest.raises(ValidationError) as exc_info:
            ReconnectionState(state="reconnecting", attempt=-1)

        assert "greater than or equal to 0" in str(exc_info.value).lower()

    def test_next_attempt_in_seconds_must_be_non_negative(self) -> None:
        """Test that next_attempt_in_seconds must be >= 0."""
        with pytest.raises(ValidationError) as exc_info:
            ReconnectionState(state="reconnecting", next_attempt_in_seconds=-5)

        assert "greater than or equal to 0" in str(exc_info.value).lower()

    def test_total_downtime_seconds_must_be_non_negative(self) -> None:
        """Test that total_downtime_seconds must be >= 0."""
        with pytest.raises(ValidationError) as exc_info:
            ReconnectionState(state="reconnecting", total_downtime_seconds=-10.5)

        assert "greater than or equal to 0" in str(exc_info.value).lower()

    def test_validate_assignment_enabled(self) -> None:
        """Test that model validates on assignment."""
        state = ReconnectionState(state="connected", attempt=0)

        with pytest.raises(ValidationError) as exc_info:
            state.attempt = -1

        assert "greater than or equal to 0" in str(exc_info.value).lower()

    def test_reconnecting_state(self) -> None:
        """Test typical reconnecting state."""
        state = ReconnectionState(
            state="reconnecting",
            attempt=3,
            next_attempt_in_seconds=8,
            total_downtime_seconds=45.2,
        )

        assert state.state == "reconnecting"
        assert state.attempt == 3
        assert state.next_attempt_in_seconds == 8
        assert state.total_downtime_seconds == 45.2

    def test_connected_state_after_reconnection(self) -> None:
        """Test state after successful reconnection."""
        now = datetime.now(UTC)
        state = ReconnectionState(
            state="connected",
            attempt=0,
            next_attempt_in_seconds=None,
            total_downtime_seconds=150.0,
            last_reconnect_timestamp=now,
        )

        assert state.state == "connected"
        assert state.attempt == 0
        assert state.next_attempt_in_seconds is None
        assert state.total_downtime_seconds == 150.0
        assert state.last_reconnect_timestamp == now

    def test_json_serialization(self) -> None:
        """Test JSON serialization of ReconnectionState."""
        now = datetime.now(UTC)
        state = ReconnectionState(
            state="reconnecting",
            attempt=5,
            next_attempt_in_seconds=32,
            total_downtime_seconds=125.5,
            last_reconnect_timestamp=now,
        )

        json_data = state.model_dump()
        assert json_data["state"] == "reconnecting"
        assert json_data["attempt"] == 5
        assert json_data["next_attempt_in_seconds"] == 32
        assert json_data["total_downtime_seconds"] == 125.5
        assert json_data["last_reconnect_timestamp"] == now

    def test_json_serialization_with_none_values(self) -> None:
        """Test JSON serialization with None values."""
        state = ReconnectionState(state="connected")

        json_data = state.model_dump()
        assert json_data["state"] == "connected"
        assert json_data["attempt"] == 0
        assert json_data["next_attempt_in_seconds"] is None
        assert json_data["total_downtime_seconds"] == 0.0
        assert json_data["last_reconnect_timestamp"] is None
