from __future__ import annotations

from datetime import datetime, timezone
from typing import Any

import pytest
from fastapi.testclient import TestClient

from backend.app.api import tracks as tracks_api
from backend.app.main import app
from backend.app.models import CombinedTrackModel, TrackModel

client = TestClient(app)


def _track_model(track_id: str = "track-1") -> TrackModel:
    now = datetime.now(timezone.utc)
    return TrackModel(
        id=track_id,
        start_station_id="station-a",
        end_station_id="station-b",
        length_meters=None,
        max_speed_kph=None,
        status="planned",
        coordinates=[(52.5, 13.4), (52.6, 13.5)],
        is_bidirectional=True,
        created_at=now,
        updated_at=now,
    )


def _combined_model(track_id: str = "combined-1") -> CombinedTrackModel:
    now = datetime.now(timezone.utc)
    return CombinedTrackModel(
        id=track_id,
        start_station_id="station-a",
        end_station_id="station-b",
        length_meters=1000,
        max_speed_kph=120,
        status="operational",
        coordinates=[(52.5, 13.4), (52.6, 13.5)],
        constituent_track_ids=["track-1", "track-2"],
        is_bidirectional=True,
        created_at=now,
        updated_at=now,
    )


def _authenticate() -> str:
    response = client.post(
        "/api/auth/login",
        json={"username": "demo", "password": "railgame123"},
    )
    assert response.status_code == 200
    return response.json()["accessToken"]


def test_list_tracks(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()
    monkeypatch.setattr(tracks_api, "list_tracks", lambda db: [_track_model()])

    response = client.get(
        "/api/tracks",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 200
    payload = response.json()
    assert isinstance(payload, list)
    assert payload[0]["id"] == "track-1"


def test_get_track_returns_404(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()
    monkeypatch.setattr(tracks_api, "get_track", lambda db, track_id: None)

    response = client.get(
        "/api/tracks/not-found",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 404


def test_create_track_calls_service(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()
    captured: dict[str, Any] = {}
    payload = {
        "startStationId": "station-a",
        "endStationId": "station-b",
        "coordinates": [[52.5, 13.4], [52.6, 13.5]],
    }

    def fake_create(db: Any, data: Any) -> TrackModel:
        assert data.start_station_id == "station-a"
        captured["payload"] = data
        return _track_model("track-new")

    monkeypatch.setattr(tracks_api, "create_track", fake_create)

    response = client.post(
        "/api/tracks",
        json=payload,
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 201
    body = response.json()
    assert body["id"] == "track-new"
    assert captured["payload"].end_station_id == "station-b"


def test_delete_track_returns_404(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()
    monkeypatch.setattr(
        tracks_api, "delete_track", lambda db, tid, regenerate=False: False
    )

    response = client.delete(
        "/api/tracks/missing",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 404


def test_delete_track_success(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()
    seen: dict[str, Any] = {}

    def fake_delete(db: Any, track_id: str, regenerate: bool = False) -> bool:
        seen["track_id"] = track_id
        seen["regenerate"] = regenerate
        return True

    monkeypatch.setattr(tracks_api, "delete_track", fake_delete)

    response = client.delete(
        "/api/tracks/track-99",
        params={"regenerate": "true"},
        headers={"Authorization": f"Bearer {token}"},
    )

    assert response.status_code == 204
    assert seen["track_id"] == "track-99"
    assert seen["regenerate"] is True


def test_list_combined_tracks(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()
    monkeypatch.setattr(
        tracks_api, "list_combined_tracks", lambda db: [_combined_model()]
    )

    response = client.get(
        "/api/tracks/combined",
        headers={"Authorization": f"Bearer {token}"},
    )
    assert response.status_code == 200
    payload = response.json()
    assert len(payload) == 1
    assert payload[0]["id"] == "combined-1"
