from __future__ import annotations

from datetime import datetime
from typing import Generic, Sequence, TypeVar

from pydantic import BaseModel, ConfigDict, Field


def to_camel(string: str) -> str:
    head, *tail = string.split("_")
    return head + "".join(part.capitalize() for part in tail)


IdT = TypeVar("IdT", bound=str)


class CamelModel(BaseModel):
    model_config = ConfigDict(
        from_attributes=True,
        populate_by_name=True,
        alias_generator=to_camel,
    )


class TimestampedModel(CamelModel):
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(
        frozen=True,
        from_attributes=True,
        populate_by_name=True,
        alias_generator=to_camel,
    )


class IdentifiedModel(TimestampedModel, Generic[IdT]):
    id: IdT


class StationModel(IdentifiedModel[str]):
    name: str
    latitude: float
    longitude: float
    code: str | None = None
    osm_id: str | None = None
    elevation_m: float | None = None
    is_active: bool = True


class TrackModel(IdentifiedModel[str]):
    start_station_id: str
    end_station_id: str
    length_meters: float
    max_speed_kph: float
    status: str | None = None
    is_bidirectional: bool = True
    coordinates: list[tuple[float, float]] = Field(default_factory=list)


class TrainModel(IdentifiedModel[str]):
    designation: str
    capacity: int
    max_speed_kph: float
    operating_track_ids: list[str]


class StationCreate(CamelModel):
    name: str
    latitude: float
    longitude: float
    osm_id: str | None = None
    code: str | None = None
    elevation_m: float | None = None
    is_active: bool = True


class StationUpdate(CamelModel):
    name: str | None = None
    latitude: float | None = None
    longitude: float | None = None
    osm_id: str | None = None
    code: str | None = None
    elevation_m: float | None = None
    is_active: bool | None = None


class TrackCreate(CamelModel):
    start_station_id: str
    end_station_id: str
    coordinates: Sequence[tuple[float, float]]
    name: str | None = None
    length_meters: float | None = None
    max_speed_kph: int | None = None
    is_bidirectional: bool = True
    status: str = "planned"


class TrainCreate(CamelModel):
    designation: str
    capacity: int
    max_speed_kph: int
    operator_id: str | None = None
    home_station_id: str | None = None
    consist: str | None = None


class TrainScheduleCreate(CamelModel):
    train_id: str
    station_id: str
    sequence_index: int
    scheduled_arrival: datetime | None = None
    scheduled_departure: datetime | None = None
    dwell_seconds: int | None = None


class UserCreate(CamelModel):
    username: str
    password_hash: str
    email: str | None = None
    full_name: str | None = None
    role: str = "player"
    preferences: str | None = None
