"""
Ride endpoints for API v1.

Provides CRUD operations for Ride entities with filtering and search.
"""
from typing import List, Optional
from uuid import UUID
from django.shortcuts import get_object_or_404
from django.db.models import Q
from ninja import Router, Query
from ninja.pagination import paginate, PageNumberPagination

from apps.entities.models import Ride, Park, Company, RideModel
from ..schemas import (
    RideCreate,
    RideUpdate,
    RideOut,
    RideListOut,
    ErrorResponse
)


router = Router(tags=["Rides"])


class RidePagination(PageNumberPagination):
    """Custom pagination for rides."""
    page_size = 50


@router.get(
    "/",
    response={200: List[RideOut]},
    summary="List rides",
    description="Get a paginated list of rides with optional filtering"
)
@paginate(RidePagination)
def list_rides(
    request,
    search: Optional[str] = Query(None, description="Search by ride name"),
    park_id: Optional[UUID] = Query(None, description="Filter by park"),
    ride_category: Optional[str] = Query(None, description="Filter by ride category"),
    status: Optional[str] = Query(None, description="Filter by status"),
    is_coaster: Optional[bool] = Query(None, description="Filter for roller coasters only"),
    manufacturer_id: Optional[UUID] = Query(None, description="Filter by manufacturer"),
    ordering: Optional[str] = Query("-created", description="Sort by field (prefix with - for descending)")
):
    """
    List all rides with optional filters.
    
    **Filters:**
    - search: Search ride names (case-insensitive partial match)
    - park_id: Filter by park
    - ride_category: Filter by ride category
    - status: Filter by operational status
    - is_coaster: Filter for roller coasters (true/false)
    - manufacturer_id: Filter by manufacturer
    - ordering: Sort results (default: -created)
    
    **Returns:** Paginated list of rides
    """
    queryset = Ride.objects.select_related('park', 'manufacturer', 'model').all()
    
    # Apply search filter
    if search:
        queryset = queryset.filter(
            Q(name__icontains=search) | Q(description__icontains=search)
        )
    
    # Apply park filter
    if park_id:
        queryset = queryset.filter(park_id=park_id)
    
    # Apply ride category filter
    if ride_category:
        queryset = queryset.filter(ride_category=ride_category)
    
    # Apply status filter
    if status:
        queryset = queryset.filter(status=status)
    
    # Apply coaster filter
    if is_coaster is not None:
        queryset = queryset.filter(is_coaster=is_coaster)
    
    # Apply manufacturer filter
    if manufacturer_id:
        queryset = queryset.filter(manufacturer_id=manufacturer_id)
    
    # Apply ordering
    valid_order_fields = ['name', 'created', 'modified', 'opening_date', 'height', 'speed', 'length']
    order_field = ordering.lstrip('-')
    if order_field in valid_order_fields:
        queryset = queryset.order_by(ordering)
    else:
        queryset = queryset.order_by('-created')
    
    # Annotate with related names
    for ride in queryset:
        ride.park_name = ride.park.name if ride.park else None
        ride.manufacturer_name = ride.manufacturer.name if ride.manufacturer else None
        ride.model_name = ride.model.name if ride.model else None
    
    return queryset


@router.get(
    "/{ride_id}",
    response={200: RideOut, 404: ErrorResponse},
    summary="Get ride",
    description="Retrieve a single ride by ID"
)
def get_ride(request, ride_id: UUID):
    """
    Get a ride by ID.
    
    **Parameters:**
    - ride_id: UUID of the ride
    
    **Returns:** Ride details
    """
    ride = get_object_or_404(
        Ride.objects.select_related('park', 'manufacturer', 'model'),
        id=ride_id
    )
    ride.park_name = ride.park.name if ride.park else None
    ride.manufacturer_name = ride.manufacturer.name if ride.manufacturer else None
    ride.model_name = ride.model.name if ride.model else None
    return ride


@router.post(
    "/",
    response={201: RideOut, 400: ErrorResponse, 404: ErrorResponse},
    summary="Create ride",
    description="Create a new ride (requires authentication)"
)
def create_ride(request, payload: RideCreate):
    """
    Create a new ride.
    
    **Authentication:** Required
    
    **Parameters:**
    - payload: Ride data
    
    **Returns:** Created ride
    """
    # TODO: Add authentication check
    # if not request.auth:
    #     return 401, {"detail": "Authentication required"}
    
    # Verify park exists
    park = get_object_or_404(Park, id=payload.park_id)
    
    # Verify manufacturer if provided
    if payload.manufacturer_id:
        get_object_or_404(Company, id=payload.manufacturer_id)
    
    # Verify model if provided
    if payload.model_id:
        get_object_or_404(RideModel, id=payload.model_id)
    
    ride = Ride.objects.create(**payload.dict())
    
    # Reload with related objects
    ride = Ride.objects.select_related('park', 'manufacturer', 'model').get(id=ride.id)
    ride.park_name = ride.park.name if ride.park else None
    ride.manufacturer_name = ride.manufacturer.name if ride.manufacturer else None
    ride.model_name = ride.model.name if ride.model else None
    
    return 201, ride


@router.put(
    "/{ride_id}",
    response={200: RideOut, 404: ErrorResponse, 400: ErrorResponse},
    summary="Update ride",
    description="Update an existing ride (requires authentication)"
)
def update_ride(request, ride_id: UUID, payload: RideUpdate):
    """
    Update a ride.
    
    **Authentication:** Required
    
    **Parameters:**
    - ride_id: UUID of the ride
    - payload: Updated ride data
    
    **Returns:** Updated ride
    """
    # TODO: Add authentication check
    # if not request.auth:
    #     return 401, {"detail": "Authentication required"}
    
    ride = get_object_or_404(
        Ride.objects.select_related('park', 'manufacturer', 'model'),
        id=ride_id
    )
    
    # Update only provided fields
    for key, value in payload.dict(exclude_unset=True).items():
        setattr(ride, key, value)
    
    ride.save()
    
    # Reload to get updated relationships
    ride = Ride.objects.select_related('park', 'manufacturer', 'model').get(id=ride.id)
    ride.park_name = ride.park.name if ride.park else None
    ride.manufacturer_name = ride.manufacturer.name if ride.manufacturer else None
    ride.model_name = ride.model.name if ride.model else None
    
    return ride


@router.patch(
    "/{ride_id}",
    response={200: RideOut, 404: ErrorResponse, 400: ErrorResponse},
    summary="Partial update ride",
    description="Partially update an existing ride (requires authentication)"
)
def partial_update_ride(request, ride_id: UUID, payload: RideUpdate):
    """
    Partially update a ride.
    
    **Authentication:** Required
    
    **Parameters:**
    - ride_id: UUID of the ride
    - payload: Fields to update
    
    **Returns:** Updated ride
    """
    # TODO: Add authentication check
    # if not request.auth:
    #     return 401, {"detail": "Authentication required"}
    
    ride = get_object_or_404(
        Ride.objects.select_related('park', 'manufacturer', 'model'),
        id=ride_id
    )
    
    # Update only provided fields
    for key, value in payload.dict(exclude_unset=True).items():
        setattr(ride, key, value)
    
    ride.save()
    
    # Reload to get updated relationships
    ride = Ride.objects.select_related('park', 'manufacturer', 'model').get(id=ride.id)
    ride.park_name = ride.park.name if ride.park else None
    ride.manufacturer_name = ride.manufacturer.name if ride.manufacturer else None
    ride.model_name = ride.model.name if ride.model else None
    
    return ride


@router.delete(
    "/{ride_id}",
    response={204: None, 404: ErrorResponse},
    summary="Delete ride",
    description="Delete a ride (requires authentication)"
)
def delete_ride(request, ride_id: UUID):
    """
    Delete a ride.
    
    **Authentication:** Required
    
    **Parameters:**
    - ride_id: UUID of the ride
    
    **Returns:** No content (204)
    """
    # TODO: Add authentication check
    # if not request.auth:
    #     return 401, {"detail": "Authentication required"}
    
    ride = get_object_or_404(Ride, id=ride_id)
    ride.delete()
    return 204, None


@router.get(
    "/coasters/",
    response={200: List[RideOut]},
    summary="List roller coasters",
    description="Get a paginated list of roller coasters only"
)
@paginate(RidePagination)
def list_coasters(
    request,
    search: Optional[str] = Query(None, description="Search by ride name"),
    park_id: Optional[UUID] = Query(None, description="Filter by park"),
    status: Optional[str] = Query(None, description="Filter by status"),
    manufacturer_id: Optional[UUID] = Query(None, description="Filter by manufacturer"),
    min_height: Optional[float] = Query(None, description="Minimum height in feet"),
    min_speed: Optional[float] = Query(None, description="Minimum speed in mph"),
    ordering: Optional[str] = Query("-height", description="Sort by field (prefix with - for descending)")
):
    """
    List only roller coasters with optional filters.
    
    **Filters:**
    - search: Search coaster names
    - park_id: Filter by park
    - status: Filter by operational status
    - manufacturer_id: Filter by manufacturer
    - min_height: Minimum height filter
    - min_speed: Minimum speed filter
    - ordering: Sort results (default: -height)
    
    **Returns:** Paginated list of roller coasters
    """
    queryset = Ride.objects.filter(is_coaster=True).select_related(
        'park', 'manufacturer', 'model'
    )
    
    # Apply search filter
    if search:
        queryset = queryset.filter(
            Q(name__icontains=search) | Q(description__icontains=search)
        )
    
    # Apply park filter
    if park_id:
        queryset = queryset.filter(park_id=park_id)
    
    # Apply status filter
    if status:
        queryset = queryset.filter(status=status)
    
    # Apply manufacturer filter
    if manufacturer_id:
        queryset = queryset.filter(manufacturer_id=manufacturer_id)
    
    # Apply height filter
    if min_height is not None:
        queryset = queryset.filter(height__gte=min_height)
    
    # Apply speed filter
    if min_speed is not None:
        queryset = queryset.filter(speed__gte=min_speed)
    
    # Apply ordering
    valid_order_fields = ['name', 'height', 'speed', 'length', 'opening_date', 'inversions']
    order_field = ordering.lstrip('-')
    if order_field in valid_order_fields:
        queryset = queryset.order_by(ordering)
    else:
        queryset = queryset.order_by('-height')
    
    # Annotate with related names
    for ride in queryset:
        ride.park_name = ride.park.name if ride.park else None
        ride.manufacturer_name = ride.manufacturer.name if ride.manufacturer else None
        ride.model_name = ride.model.name if ride.model else None
    
    return queryset
