from __future__ import annotations

from datetime import datetime, timezone
from typing import Any
from uuid import uuid4

import pytest
from fastapi.testclient import TestClient

from backend.app.api import stations as stations_api
from backend.app.main import app
from backend.app.models import StationCreate, StationModel, StationUpdate

AUTH_CREDENTIALS = {"username": "demo", "password": "railgame123"}

client = TestClient(app)


def _authenticate() -> str:
    response = client.post("/api/auth/login", json=AUTH_CREDENTIALS)
    assert response.status_code == 200
    return response.json()["accessToken"]


def _station_payload(**overrides: Any) -> dict[str, Any]:
    payload = {
        "name": "Central",
        "latitude": 52.52,
        "longitude": 13.405,
        "osmId": "123",
        "code": "BER",
        "elevationM": 34.5,
        "isActive": True,
    }
    payload.update(overrides)
    return payload


def _station_model(**overrides: Any) -> StationModel:
    now = datetime.now(timezone.utc)
    base = StationModel(
        id=str(uuid4()),
        name="Central",
        latitude=52.52,
        longitude=13.405,
        code="BER",
        osm_id="123",
        elevation_m=34.5,
        is_active=True,
        created_at=now,
        updated_at=now,
    )
    return base.model_copy(update=overrides)


def test_list_stations_requires_authentication() -> None:
    response = client.get("/api/stations")
    assert response.status_code == 401


def test_list_stations_returns_payload(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()

    def fake_list_stations(db, include_inactive: bool) -> list[StationModel]:
        assert include_inactive is True
        return [_station_model()]

    monkeypatch.setattr(stations_api, "list_stations", fake_list_stations)

    response = client.get(
        "/api/stations",
        params={"include_inactive": "true"},
        headers={"Authorization": f"Bearer {token}"},
    )

    assert response.status_code == 200
    payload = response.json()
    assert len(payload) == 1
    assert payload[0]["name"] == "Central"


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

    def fake_create_station(db, payload: StationCreate) -> StationModel:
        seen["payload"] = payload
        return _station_model()

    monkeypatch.setattr(stations_api, "create_station", fake_create_station)

    response = client.post(
        "/api/stations",
        json=_station_payload(),
        headers={"Authorization": f"Bearer {token}"},
    )

    assert response.status_code == 201
    assert response.json()["name"] == "Central"
    assert seen["payload"].name == "Central"


def test_update_station_not_found_returns_404(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()

    def fake_update_station(
        db, station_id: str, payload: StationUpdate
    ) -> StationModel:
        raise LookupError("Station not found")

    monkeypatch.setattr(stations_api, "update_station", fake_update_station)

    response = client.put(
        "/api/stations/123e4567-e89b-12d3-a456-426614174000",
        json={"name": "New Name"},
        headers={"Authorization": f"Bearer {token}"},
    )

    assert response.status_code == 404
    assert response.json()["detail"] == "Station not found"


def test_archive_station_returns_updated_model(monkeypatch: pytest.MonkeyPatch) -> None:
    token = _authenticate()

    def fake_archive_station(db, station_id: str) -> StationModel:
        return _station_model(is_active=False)

    monkeypatch.setattr(stations_api, "archive_station", fake_archive_station)

    response = client.post(
        "/api/stations/123e4567-e89b-12d3-a456-426614174000/archive",
        headers={"Authorization": f"Bearer {token}"},
    )

    assert response.status_code == 200
    assert response.json()["isActive"] is False
