"""
Ride Model
Ride booking, status management, and location tracking
"""
import enum
from datetime import datetime
from typing import Optional, List
from sqlalchemy import (
    String, Integer, Float, Boolean, Enum, Text, DateTime,
    ForeignKey, Index, JSON
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.models.base import BaseModel


class RideStatus(str, enum.Enum):
    """Ride lifecycle status"""
    REQUESTED = "requested"        # Passenger requested ride
    SEARCHING = "searching"        # Looking for drivers
    BIDDING = "bidding"           # Drivers submitting bids
    ACCEPTED = "accepted"          # Driver accepted
    DRIVER_ARRIVED = "driver_arrived"  # Driver at pickup
    STARTED = "started"            # Ride in progress
    COMPLETED = "completed"        # Ride finished
    CANCELLED = "cancelled"        # Cancelled by passenger or driver
    NO_DRIVERS = "no_drivers"      # No drivers available
    EXPIRED = "expired"            # Request expired


class RideType(str, enum.Enum):
    """Ride type enumeration"""
    ONE_WAY = "one_way"
    ROUND_TRIP = "round_trip"
    SCHEDULED = "scheduled"
    PER_HOUR = "per_hour"
    DELIVERY = "delivery"


class CancellationReason(str, enum.Enum):
    """Predefined cancellation reasons"""
    PASSENGER_CHANGED_MIND = "passenger_changed_mind"
    DRIVER_TOO_FAR = "driver_too_far"
    DRIVER_NOT_RESPONDING = "driver_not_responding"
    WRONG_ADDRESS = "wrong_address"
    VEHICLE_ISSUE = "vehicle_issue"
    EMERGENCY = "emergency"
    FOUND_ANOTHER_RIDE = "found_another_ride"
    DRIVER_CANCELLED = "driver_cancelled"
    PASSENGER_NO_SHOW = "passenger_no_show"
    OTHER = "other"


class Ride(BaseModel):
    """
    Ride model with pickup/dropoff locations, fare, and status tracking.
    Supports one-way, round-trip, and scheduled rides.
    """
    __tablename__ = "rides"
    
    # Unique ride identifier
    ride_code: Mapped[str] = mapped_column(
        String(20),
        unique=True,
        nullable=False,
        index=True
    )
    
    # Passenger and Driver
    passenger_id: Mapped[int] = mapped_column(
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    driver_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("drivers.id", ondelete="SET NULL"),
        nullable=True,
        index=True
    )
    vehicle_category_id: Mapped[int] = mapped_column(
        ForeignKey("vehicle_categories.id", ondelete="RESTRICT"),
        nullable=False
    )
    
    # Ride Type and Status
    ride_type: Mapped[RideType] = mapped_column(
        Enum(RideType),
        default=RideType.ONE_WAY,
        nullable=False
    )
    status: Mapped[RideStatus] = mapped_column(
        Enum(RideStatus),
        default=RideStatus.REQUESTED,
        nullable=False,
        index=True
    )
    
    # Pickup Location
    pickup_address: Mapped[str] = mapped_column(Text, nullable=False)
    pickup_latitude: Mapped[float] = mapped_column(Float(precision=10), nullable=False)
    pickup_longitude: Mapped[float] = mapped_column(Float(precision=10), nullable=False)
    pickup_place_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    
    # Dropoff Location
    dropoff_address: Mapped[str] = mapped_column(Text, nullable=False)
    dropoff_latitude: Mapped[float] = mapped_column(Float(precision=10), nullable=False)
    dropoff_longitude: Mapped[float] = mapped_column(Float(precision=10), nullable=False)
    dropoff_place_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    
    # Return Location (for round trips)
    return_address: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    return_latitude: Mapped[Optional[float]] = mapped_column(Float(precision=10), nullable=True)
    return_longitude: Mapped[Optional[float]] = mapped_column(Float(precision=10), nullable=True)
    
    # Scheduling
    is_scheduled: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    scheduled_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    
    # Distance and Duration
    estimated_distance_km: Mapped[float] = mapped_column(Float, default=0, nullable=False)
    estimated_duration_minutes: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    actual_distance_km: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    actual_duration_minutes: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    
    # Fare (in cents/paise)
    estimated_fare: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    final_fare: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    accepted_bid_amount: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    base_fare: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    distance_fare: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    time_fare: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    surge_multiplier: Mapped[float] = mapped_column(Float, default=1.0, nullable=False)
    promo_discount: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    
    # Payment
    payment_method: Mapped[str] = mapped_column(String(50), default="cash", nullable=False)
    payment_status: Mapped[str] = mapped_column(String(50), default="pending", nullable=False)
    promo_code_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("promo_codes.id", ondelete="SET NULL"),
        nullable=True
    )
    
    # Commission
    commission_percentage: Mapped[float] = mapped_column(Float, default=15.0, nullable=False)
    commission_amount: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    driver_earnings: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    
    # Timestamps
    requested_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
    accepted_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    driver_arrived_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    started_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    completed_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    cancelled_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    
    # Cancellation
    cancelled_by: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)  # passenger/driver/system
    cancellation_reason: Mapped[Optional[CancellationReason]] = mapped_column(
        Enum(CancellationReason),
        nullable=True
    )
    cancellation_note: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    cancellation_fee: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    
    # Route (stored as JSON polyline or coordinates)
    route_polyline: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    route_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    
    # Passenger count
    passenger_count: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
    
    # Notes
    passenger_notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    driver_notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    
    # Relationships
    passenger: Mapped["User"] = relationship(
        "User",
        foreign_keys=[passenger_id],
        lazy="joined"
    )
    driver: Mapped[Optional["Driver"]] = relationship(
        "Driver",
        foreign_keys=[driver_id],
        lazy="joined"
    )
    vehicle_category: Mapped["VehicleCategory"] = relationship(
        "VehicleCategory",
        lazy="joined"
    )
    bids: Mapped[List["FareBid"]] = relationship(
        "FareBid",
        back_populates="ride",
        lazy="dynamic"
    )
    rating: Mapped[Optional["Rating"]] = relationship(
        "Rating",
        back_populates="ride",
        uselist=False,
        lazy="joined"
    )
    promo_code: Mapped[Optional["PromoCode"]] = relationship(
        "PromoCode",
        lazy="joined"
    )
    
    # Indexes
    __table_args__ = (
        Index('idx_ride_passenger_status', 'passenger_id', 'status'),
        Index('idx_ride_driver_status', 'driver_id', 'status'),
        Index('idx_ride_status_created', 'status', 'created_at'),
        Index('idx_ride_scheduled', 'is_scheduled', 'scheduled_at'),
    )


# Import for type hints
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from app.models.user import User
    from app.models.driver import Driver
    from app.models.vehicle import VehicleCategory
    from app.models.fare_bid import FareBid
    from app.models.rating import Rating
    from app.models.promo import PromoCode
