"""Tests for domain schemas and configuration."""

from datetime import datetime, timezone

import pytest
from pydantic import ValidationError

from gps_denied.config import get_settings
from gps_denied.schemas import CameraParameters, GPSPoint
from gps_denied.schemas.events import (
    FrameProcessedEvent,
    SSEEventType,
    SSEMessage,
)
from gps_denied.schemas.flight import (
    FlightCreateRequest,
    Waypoint,
)

# ── GPSPoint ──────────────────────────────────────────────────────────────

class TestGPSPoint:
    def test_valid(self):
        p = GPSPoint(lat=48.275, lon=37.385)
        assert p.lat == 48.275

    def test_lat_out_of_range(self):
        with pytest.raises(ValidationError):
            GPSPoint(lat=91, lon=0)

    def test_lon_out_of_range(self):
        with pytest.raises(ValidationError):
            GPSPoint(lat=0, lon=181)

    def test_serialization_roundtrip(self):
        p = GPSPoint(lat=-12.5, lon=130.0)
        assert GPSPoint.model_validate_json(p.model_dump_json()) == p


# ── CameraParameters ─────────────────────────────────────────────────────

class TestCameraParameters:
    def test_valid(self):
        cam = CameraParameters(
            focal_length=25,
            sensor_width=23.5,
            sensor_height=15.6,
            resolution_width=6252,
            resolution_height=4168,
        )
        assert cam.resolution_width == 6252

    def test_negative_focal_length(self):
        with pytest.raises(ValidationError):
            CameraParameters(
                focal_length=-1,
                sensor_width=23.5,
                sensor_height=15.6,
                resolution_width=6252,
                resolution_height=4168,
            )


# ── FlightCreateRequest ──────────────────────────────────────────────────

class TestFlightCreateRequest:
    def test_minimal_valid(self):
        req = FlightCreateRequest(
            name="Test_Flight",
            start_gps=GPSPoint(lat=48.275, lon=37.385),
            camera_params=CameraParameters(
                focal_length=25,
                sensor_width=23.5,
                sensor_height=15.6,
                resolution_width=6252,
                resolution_height=4168,
            ),
            altitude=400,
        )
        assert req.name == "Test_Flight"
        assert req.description == ""
        assert req.geofences.polygons == []

    def test_empty_name_rejected(self):
        with pytest.raises(ValidationError):
            FlightCreateRequest(
                name="",
                start_gps=GPSPoint(lat=0, lon=0),
                camera_params=CameraParameters(
                    focal_length=25,
                    sensor_width=23.5,
                    sensor_height=15.6,
                    resolution_width=6252,
                    resolution_height=4168,
                ),
                altitude=400,
            )


# ── Waypoint ──────────────────────────────────────────────────────────────

class TestWaypoint:
    def test_valid(self):
        wp = Waypoint(
            id="wp_001",
            lat=48.123,
            lon=37.456,
            confidence=0.95,
            timestamp=datetime.now(tz=timezone.utc),
        )
        assert wp.refined is False

    def test_confidence_out_of_range(self):
        with pytest.raises(ValidationError):
            Waypoint(
                id="wp_001",
                lat=48.123,
                lon=37.456,
                confidence=1.5,
                timestamp=datetime.now(tz=timezone.utc),
            )


# ── SSE Events ────────────────────────────────────────────────────────────

class TestSSEEvents:
    def test_event_types(self):
        assert SSEEventType.FRAME_PROCESSED == "frame_processed"
        assert SSEEventType.FLIGHT_COMPLETED == "flight_completed"

    def test_frame_event_serialization(self):
        evt = FrameProcessedEvent(
            frame_id=237,
            gps=GPSPoint(lat=48.123, lon=37.456),
            confidence=0.95,
            timestamp=datetime.now(tz=timezone.utc),
        )
        data = evt.model_dump()
        assert data["frame_id"] == 237

    def test_sse_message(self):
        msg = SSEMessage(
            event=SSEEventType.FLIGHT_COMPLETED,
            data={"frames_total": 100, "frames_processed": 100},
        )
        assert msg.event == "flight_completed"


# ── Configuration ─────────────────────────────────────────────────────────

class TestConfig:
    def test_defaults(self):
        settings = get_settings()
        assert "sqlite" in settings.db.url
        assert settings.api.port == 8000
        assert settings.tiles.provider == "google"

    def test_rotation_iterations(self):
        settings = get_settings()
        assert settings.rotation.rotation_iterations == 12  # 360 / 30

    def test_recovery_defaults(self):
        settings = get_settings()
        assert settings.recovery.search_grid_sizes == [1, 4, 9, 16, 25]
