"""
Tests for laneswap.server module.

This module tests the built-in HTTP server for framework-free integration.
"""

import json
import time
from http.client import HTTPConnection
from typing import Any, Dict
from unittest.mock import Mock, patch

import pytest

from laneswap.server import HealthHTTPRequestHandler, start_health_server


class TestHealthHTTPRequestHandler:
    """Test HealthHTTPRequestHandler class."""

    def test_handler_has_laneswap_instance_attribute(self) -> None:
        """Test that handler class has laneswap_instance class variable."""
        assert hasattr(HealthHTTPRequestHandler, "laneswap_instance")


class TestStartHealthServer:
    """Test start_health_server function."""

    def test_starts_server_thread(self, free_port: int, clean_env: None) -> None:
        """Test that start_health_server starts a daemon thread."""
        from laneswap import LaneSwap

        laneswap = LaneSwap(port=free_port, setup_signals=False)

        thread = start_health_server(laneswap)

        assert thread is not None
        assert thread.is_alive()
        assert thread.daemon is True

        # Cleanup
        laneswap._running = False
        thread.join(timeout=1)

    def test_server_responds_to_health_requests(
        self, free_port: int, clean_env: None
    ) -> None:
        """Test that server responds to HTTP health check requests."""
        from laneswap import LaneSwap

        laneswap = LaneSwap(port=free_port, setup_signals=False, setup_logs=False)

        @laneswap.health_check
        def check() -> Dict[str, str]:
            return {"component": "test"}

        thread = start_health_server(laneswap)
        time.sleep(0.2)  # Give server time to start

        try:
            # Make HTTP request
            conn = HTTPConnection("localhost", free_port, timeout=2)
            conn.request("GET", "/health")
            response = conn.getresponse()
            data = json.loads(response.read().decode("utf-8"))

            assert response.status == 200
            assert data["status"] == "healthy"
            assert data["service"] == "service"
            assert data["component"] == "test"
            assert "timestamp" in data

        finally:
            # Cleanup
            laneswap._running = False
            conn.close()
            thread.join(timeout=1)

    def test_server_returns_404_for_unknown_paths(
        self, free_port: int, clean_env: None
    ) -> None:
        """Test that server returns 404 for non-health endpoints."""
        from laneswap import LaneSwap

        laneswap = LaneSwap(port=free_port, setup_signals=False, setup_logs=False)
        thread = start_health_server(laneswap)
        time.sleep(0.2)

        try:
            conn = HTTPConnection("localhost", free_port, timeout=2)
            conn.request("GET", "/unknown")
            response = conn.getresponse()
            data = json.loads(response.read().decode("utf-8"))

            assert response.status == 404
            assert data["status"] == "unhealthy"
            assert "error" in data

        finally:
            laneswap._running = False
            conn.close()
            thread.join(timeout=1)

    def test_server_handles_multiple_requests(
        self, free_port: int, clean_env: None
    ) -> None:
        """Test that server can handle multiple sequential requests."""
        from laneswap import LaneSwap

        laneswap = LaneSwap(port=free_port, setup_signals=False, setup_logs=False)
        thread = start_health_server(laneswap)
        time.sleep(0.2)

        try:
            for _ in range(3):
                conn = HTTPConnection("localhost", free_port, timeout=2)
                conn.request("GET", "/health")
                response = conn.getresponse()
                response.read()  # Consume response
                conn.close()

                assert response.status == 200

        finally:
            laneswap._running = False
            thread.join(timeout=1)

    def test_server_includes_custom_health_checks(
        self, free_port: int, clean_env: None
    ) -> None:
        """Test that server includes custom health check results."""
        from laneswap import LaneSwap

        laneswap = LaneSwap(port=free_port, setup_signals=False, setup_logs=False)

        @laneswap.health_check
        def check_db() -> Dict[str, str]:
            return {"database": "connected"}

        @laneswap.health_check
        def check_cache() -> Dict[str, str]:
            return {"cache": "ready"}

        thread = start_health_server(laneswap)
        time.sleep(0.2)

        try:
            conn = HTTPConnection("localhost", free_port, timeout=2)
            conn.request("GET", "/health")
            response = conn.getresponse()
            data = json.loads(response.read().decode("utf-8"))

            assert data["database"] == "connected"
            assert data["cache"] == "ready"

        finally:
            laneswap._running = False
            conn.close()
            thread.join(timeout=1)

    def test_server_stops_when_running_false(
        self, free_port: int, clean_env: None
    ) -> None:
        """Test that server stops when laneswap.running is set to False."""
        from laneswap import LaneSwap

        laneswap = LaneSwap(port=free_port, setup_signals=False, setup_logs=False)
        thread = start_health_server(laneswap)
        time.sleep(0.2)

        assert thread.is_alive()

        # Stop server
        laneswap._running = False

        # Make one more request to trigger the loop check
        try:
            conn = HTTPConnection("localhost", free_port, timeout=1)
            conn.request("GET", "/health")
            conn.getresponse()
            conn.close()
        except:
            pass  # Connection may fail as server is shutting down

        thread.join(timeout=2)
        assert not thread.is_alive()

    def test_server_sets_class_variable(self, free_port: int, clean_env: None) -> None:
        """Test that start_health_server sets HealthHTTPRequestHandler class variable."""
        from laneswap import LaneSwap

        laneswap = LaneSwap(port=free_port, setup_signals=False, setup_logs=False)
        thread = start_health_server(laneswap)

        assert HealthHTTPRequestHandler.laneswap_instance is laneswap

        # Cleanup
        laneswap._running = False
        thread.join(timeout=1)

    def test_server_binds_to_all_interfaces(
        self, free_port: int, clean_env: None
    ) -> None:
        """Test that server binds to 0.0.0.0 (all interfaces)."""
        from laneswap import LaneSwap

        laneswap = LaneSwap(port=free_port, setup_signals=False, setup_logs=False)
        thread = start_health_server(laneswap)
        time.sleep(0.2)

        try:
            # Test connection via localhost
            conn = HTTPConnection("127.0.0.1", free_port, timeout=2)
            conn.request("GET", "/health")
            response = conn.getresponse()
            response.read()

            assert response.status == 200

        finally:
            laneswap._running = False
            conn.close()
            thread.join(timeout=1)
