"""
Ride Routes
Ride booking, fare estimation, bidding, and status management
"""
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from sqlalchemy.orm import selectinload

from app.database import get_db
from app.models.user import User, UserRole
from app.models.ride import Ride, RideStatus
from app.models.fare_bid import FareBid, BidStatus
from app.models.vehicle import VehicleCategory
from app.schemas.ride import (
    RideCreate,
    RideResponse,
    FareEstimateRequest,
    FareEstimateResponse,
    FareBidResponse,
    FareBidAction,
    RideStatusUpdate,
    RideCancelRequest,
    VehicleCategoryResponse,
)
from app.schemas.common import MessageResponse, PaginatedResponse
from app.services.ride_service import RideService
from app.utils.helpers import build_order_by
from app.services.map_provider import get_map_provider, MapProvider
from app.utils.dependencies import get_current_user, require_role
from app.routes.websocket import publish_ride_event

router = APIRouter()


@router.get("/categories", response_model=List[VehicleCategoryResponse])
async def get_vehicle_categories(
    db: AsyncSession = Depends(get_db)
):
    """Get available vehicle categories"""
    query = select(VehicleCategory).where(
        VehicleCategory.is_active == True
    ).order_by(VehicleCategory.sort_order)
    
    result = await db.execute(query)
    categories = result.scalars().all()
    
    return [
        VehicleCategoryResponse(
            id=c.id,
            name=c.name,
            display_name=c.display_name,
            description=c.description,
            icon_url=c.icon_url,
            max_passengers=c.max_passengers,
            max_luggage=c.max_luggage,
            luggage_capacity=c.max_luggage,
            base_fare=c.base_fare,
            per_km_rate=c.per_km_rate,
            per_minute_rate=c.per_minute_rate,
            minimum_fare=c.minimum_fare,
        )
        for c in categories
    ]


@router.post("/estimate", response_model=FareEstimateResponse)
async def estimate_fare(
    data: FareEstimateRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    map_provider: MapProvider = Depends(get_map_provider)
):
    """
    Get fare estimation for a ride.
    
    Returns estimated distance, duration, and fare breakdown.
    """
    try:
        estimate = await RideService.estimate_fare(db, map_provider, data)
        return estimate
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


@router.post("/book", response_model=RideResponse, status_code=status.HTTP_201_CREATED)
async def book_ride(
    data: RideCreate,
    current_user: User = Depends(require_role(UserRole.PASSENGER)),
    db: AsyncSession = Depends(get_db),
    map_provider: MapProvider = Depends(get_map_provider)
):
    """
    Book a new ride.
    
    After booking, drivers in the area will receive the request and can submit bids.
    """
    try:
        ride = await RideService.create_ride(db, map_provider, current_user.id, data)
        await publish_ride_event(ride, "ride_requested")
        
        return await _build_ride_response(ride, db)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


@router.get("/{ride_id}", response_model=RideResponse)
async def get_ride(
    ride_id: int,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Get ride details by ID"""
    ride = await RideService.get_ride_by_id(db, ride_id, current_user.id)
    
    if not ride:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Ride not found")
    
    return await _build_ride_response(ride, db)


@router.get("/{ride_id}/bids", response_model=PaginatedResponse[FareBidResponse])
async def get_ride_bids(
    ride_id: int,
    page: int = Query(1, ge=1),
    limit: int = Query(20, ge=1, le=100),
    sort_by: str = Query("created_at", description="Field to sort by"),
    order: str = Query("desc", description="Sort order: asc or desc"),
    current_user: User = Depends(require_role(UserRole.PASSENGER)),
    db: AsyncSession = Depends(get_db)
):
    """Get all pending bids for a ride"""
    ride_query = select(Ride).where(
        Ride.id == ride_id,
        Ride.passenger_id == current_user.id
    )
    ride_result = await db.execute(ride_query)
    ride = ride_result.scalar_one_or_none()
    
    if not ride:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Ride not found")
    
    bid_filter = (FareBid.ride_id == ride_id) & (FareBid.status == BidStatus.PENDING)
    count_result = await db.execute(select(func.count(FareBid.id)).where(bid_filter))
    total = count_result.scalar() or 0

    offset = (page - 1) * limit
    order_clause = build_order_by(FareBid, sort_by, order, {"created_at", "submitted_at", "bid_amount", "id"})
    query = select(FareBid).where(bid_filter).options(selectinload(FareBid.driver)).order_by(order_clause).offset(offset).limit(limit)
    result = await db.execute(query)
    bids = result.scalars().all()
    
    items = [
        FareBidResponse(
            id=bid.id,
            ride_id=bid.ride_id,
            driver_id=bid.driver_id,
            driver_name=bid.driver.user.full_name,
            driver_photo=bid.driver.user.profile_picture,
            driver_rating=bid.driver.average_rating,
            driver_total_rides=bid.driver.total_rides,
            bid_amount=bid.bid_amount,
            original_fare=bid.original_fare,
            bid_percentage=bid.bid_percentage,
            status=bid.status,
            message=bid.message,
            estimated_arrival_minutes=bid.estimated_arrival_minutes,
            driver_distance_km=bid.driver_distance_km,
            vehicle_make=bid.driver.current_vehicle.make if bid.driver.current_vehicle else None,
            vehicle_model=bid.driver.current_vehicle.model if bid.driver.current_vehicle else None,
            vehicle_color=bid.driver.current_vehicle.color if bid.driver.current_vehicle else None,
            vehicle_plate=bid.driver.current_vehicle.license_plate if bid.driver.current_vehicle else None,
            submitted_at=bid.submitted_at,
            expires_at=bid.expires_at
        )
        for bid in bids
    ]
    return PaginatedResponse.create(items, total, page, limit)


@router.post("/{ride_id}/bids/{bid_id}/accept", response_model=RideResponse)
async def accept_bid(
    ride_id: int,
    bid_id: int,
    current_user: User = Depends(require_role(UserRole.PASSENGER)),
    db: AsyncSession = Depends(get_db)
):
    """Accept a fare bid from a driver"""
    try:
        ride = await RideService.accept_bid(db, ride_id, bid_id, current_user.id)
        await publish_ride_event(
            ride,
            "ride_accepted",
            {"bid_id": bid_id, "accepted_by": "passenger"},
        )
        
        return await _build_ride_response(ride, db)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


@router.put("/{ride_id}/status", response_model=RideResponse)
async def update_ride_status(
    ride_id: int,
    data: RideStatusUpdate,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Update ride status (driver actions)"""
    try:
        is_driver = current_user.role == UserRole.DRIVER
        ride = await RideService.update_ride_status(
            db, ride_id, data.status, current_user.id, is_driver
        )
        await publish_ride_event(
            ride,
            "ride_status_changed",
            {
                "status": data.status.value if hasattr(data.status, "value") else str(data.status),
                "updated_by": "driver" if is_driver else "passenger",
            },
        )
        return await _build_ride_response(ride, db)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


@router.post("/{ride_id}/cancel", response_model=MessageResponse)
async def cancel_ride(
    ride_id: int,
    data: RideCancelRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    """Cancel a ride"""
    query = select(Ride).where(Ride.id == ride_id)
    result = await db.execute(query)
    ride = result.scalar_one_or_none()
    
    if not ride:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Ride not found")
    
    # Check if cancellable
    if ride.status in [RideStatus.COMPLETED, RideStatus.CANCELLED]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ride cannot be cancelled"
        )
    
    # Determine who is cancelling
    cancelled_by = "passenger" if ride.passenger_id == current_user.id else "driver"
    
    ride.status = RideStatus.CANCELLED
    ride.cancelled_at = datetime.utcnow()
    ride.cancelled_by = cancelled_by
    ride.cancellation_reason = data.reason
    ride.cancellation_note = data.note
    
    # Release driver if assigned
    if ride.driver:
        ride.driver.is_on_ride = False
    
    await db.commit()
    await db.refresh(ride)
    await publish_ride_event(
        ride,
        "ride_cancelled",
        {
            "reason": data.reason.value if hasattr(data.reason, "value") else str(data.reason),
            "cancelled_by": cancelled_by,
            "note": data.note,
        },
    )
    
    return MessageResponse(message="Ride cancelled successfully")


async def _build_ride_response(ride: Ride, db: AsyncSession) -> RideResponse:
    """Helper to build RideResponse with all related data"""
    # Load relationships if not loaded
    if not ride.vehicle_category:
        await db.refresh(ride, ["vehicle_category", "driver", "passenger", "rating"])
    
    pending_bids_count = None
    if ride.status in [RideStatus.REQUESTED, RideStatus.BIDDING]:
        from sqlalchemy import func
        count_query = select(func.count()).select_from(FareBid).where(
            FareBid.ride_id == ride.id,
            FareBid.status == BidStatus.PENDING
        )
        count_result = await db.execute(count_query)
        pending_bids_count = count_result.scalar()
    
    return RideResponse(
        id=ride.id,
        ride_code=ride.ride_code,
        ride_type=ride.ride_type,
        status=ride.status,
        pickup_address=ride.pickup_address,
        pickup_latitude=ride.pickup_latitude,
        pickup_longitude=ride.pickup_longitude,
        dropoff_address=ride.dropoff_address,
        dropoff_latitude=ride.dropoff_latitude,
        dropoff_longitude=ride.dropoff_longitude,
        estimated_distance_km=ride.estimated_distance_km,
        estimated_duration_minutes=ride.estimated_duration_minutes,
        actual_distance_km=ride.actual_distance_km,
        actual_duration_minutes=ride.actual_duration_minutes,
        estimated_fare=ride.estimated_fare,
        final_fare=ride.final_fare,
        accepted_bid_amount=ride.accepted_bid_amount,
        payment_method=ride.payment_method,
        payment_status=ride.payment_status,
        promo_discount=ride.promo_discount,
        requested_at=ride.requested_at,
        accepted_at=ride.accepted_at,
        started_at=ride.started_at,
        completed_at=ride.completed_at,
        cancelled_at=ride.cancelled_at,
        is_scheduled=ride.is_scheduled,
        scheduled_at=ride.scheduled_at,
        vehicle_category_id=ride.vehicle_category_id,
        vehicle_category_name=ride.vehicle_category.display_name if ride.vehicle_category else None,
        passenger_id=ride.passenger_id,
        passenger_name=ride.passenger.full_name if ride.passenger else None,
        driver_id=ride.driver_id,
        driver_name=ride.driver.user.full_name if ride.driver else None,
        driver_phone=ride.driver.user.phone if ride.driver else None,
        driver_photo=ride.driver.user.profile_picture if ride.driver else None,
        driver_rating=ride.driver.average_rating if ride.driver else None,
        vehicle_make=ride.driver.current_vehicle.make if ride.driver and ride.driver.current_vehicle else None,
        vehicle_model=ride.driver.current_vehicle.model if ride.driver and ride.driver.current_vehicle else None,
        vehicle_color=ride.driver.current_vehicle.color if ride.driver and ride.driver.current_vehicle else None,
        vehicle_plate=ride.driver.current_vehicle.license_plate if ride.driver and ride.driver.current_vehicle else None,
        cancelled_by=ride.cancelled_by,
        cancellation_reason=ride.cancellation_reason,
        rating_given=ride.rating.driver_rating if ride.rating else None,
        rating_received=ride.rating.passenger_rating if ride.rating else None,
        pending_bids_count=pending_bids_count,
        created_at=ride.created_at
    )


# Add datetime import at top
from datetime import datetime
