from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from backend.app.api.deps import get_current_user, get_db
from backend.app.models import (
    CombinedTrackModel,
    TrackCreate,
    TrackUpdate,
    TrackModel,
    UserPublic,
)
from backend.app.services.combined_tracks import (
    create_combined_track,
    get_combined_track,
    list_combined_tracks,
)
from backend.app.services.tracks import (
    create_track,
    delete_track,
    regenerate_combined_tracks,
    update_track,
    get_track,
    list_tracks,
)

router = APIRouter(prefix="/tracks", tags=["tracks"])


@router.get("", response_model=list[TrackModel])
def read_combined_tracks(
    _: UserPublic = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> list[TrackModel]:
    """Return all base tracks."""
    return list_tracks(db)


@router.get("/combined", response_model=list[CombinedTrackModel])
def read_combined_tracks_combined(
    _: UserPublic = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> list[CombinedTrackModel]:
    return list_combined_tracks(db)


@router.get("/{track_id}", response_model=TrackModel)
def read_track(
    track_id: str,
    _: UserPublic = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> TrackModel:
    track = get_track(db, track_id)
    if track is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Track {track_id} not found",
        )
    return track


@router.get("/combined/{combined_track_id}", response_model=CombinedTrackModel)
def read_combined_track(
    combined_track_id: str,
    _: UserPublic = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> CombinedTrackModel:
    combined_track = get_combined_track(db, combined_track_id)
    if combined_track is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Combined track {combined_track_id} not found",
        )
    return combined_track


@router.post("", response_model=TrackModel, status_code=status.HTTP_201_CREATED)
def create_track_endpoint(
    payload: TrackCreate,
    regenerate: bool = False,
    _: UserPublic = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> TrackModel:
    try:
        track = create_track(db, payload)
    except ValueError as exc:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)
        ) from exc

    if regenerate:
        regenerate_combined_tracks(
            db, [track.start_station_id, track.end_station_id])

    return track


@router.post(
    "/combined",
    response_model=CombinedTrackModel,
    status_code=status.HTTP_201_CREATED,
    summary="Create a combined track between two stations using pathfinding",
)
def create_combined_track_endpoint(
    start_station_id: str,
    end_station_id: str,
    _: UserPublic = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> CombinedTrackModel:
    combined_track = create_combined_track(
        db, start_station_id, end_station_id)
    if combined_track is None:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Could not create combined track: no path exists between stations or track already exists",
        )
    return combined_track


@router.put("/{track_id}", response_model=TrackModel)
def update_track_endpoint(
    track_id: str,
    payload: TrackUpdate,
    regenerate: bool = False,
    _: UserPublic = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> TrackModel:
    track = update_track(db, track_id, payload)
    if track is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Track {track_id} not found",
        )
    if regenerate:
        regenerate_combined_tracks(
            db, [track.start_station_id, track.end_station_id])
    return track


@router.delete("/{track_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_track_endpoint(
    track_id: str,
    regenerate: bool = False,
    _: UserPublic = Depends(get_current_user),
    db: Session = Depends(get_db),
) -> None:
    deleted = delete_track(db, track_id, regenerate=regenerate)
    if not deleted:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Track {track_id} not found",
        )
