"""
Promo Code Models
Promotional codes and usage tracking
"""
import enum
from datetime import datetime
from typing import Optional, List
from sqlalchemy import (
    String, Integer, Float, Boolean, Enum, Text, DateTime,
    ForeignKey, Index
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.models.base import BaseModel


class PromoType(str, enum.Enum):
    """Promo code type"""
    PERCENTAGE = "percentage"  # Percentage discount
    FIXED = "fixed"           # Fixed amount discount
    FREE_RIDE = "free_ride"   # Completely free ride


class PromoCode(BaseModel):
    """
    Promotional code configuration.
    Supports percentage, fixed amount, and free ride promos.
    """
    __tablename__ = "promo_codes"
    
    # Promo code (unique identifier)
    code: Mapped[str] = mapped_column(
        String(50),
        unique=True,
        nullable=False,
        index=True
    )
    
    # Display info
    title: Mapped[str] = mapped_column(String(255), nullable=False)
    description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    
    # Discount configuration
    promo_type: Mapped[PromoType] = mapped_column(
        Enum(PromoType),
        default=PromoType.PERCENTAGE,
        nullable=False
    )
    discount_value: Mapped[float] = mapped_column(Float, nullable=False)  # % or cents
    min_order_value: Mapped[int] = mapped_column(Integer, default=0, nullable=False)  # Minimum fare
    max_discount: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)  # Max discount cap
    
    # Usage limits
    total_usage_limit: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    per_user_limit: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
    current_usage_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    
    # Validity period
    valid_from: Mapped[datetime] = mapped_column(DateTime, nullable=False)
    valid_until: Mapped[datetime] = mapped_column(DateTime, nullable=False)
    
    # Targeting
    for_new_users_only: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    applicable_vehicle_categories: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)  # CSV IDs
    applicable_cities: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)  # CSV city names
    
    # Status
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
    
    # Created by (admin)
    created_by: Mapped[Optional[int]] = mapped_column(
        ForeignKey("users.id", ondelete="SET NULL"),
        nullable=True
    )
    
    # Relationships
    usages: Mapped[List["PromoUsage"]] = relationship(
        "PromoUsage",
        back_populates="promo_code",
        lazy="dynamic"
    )
    
    # Indexes
    __table_args__ = (
        Index('idx_promo_code_active', 'code', 'is_active'),
        Index('idx_promo_validity', 'valid_from', 'valid_until'),
    )
    
    @property
    def is_valid(self) -> bool:
        """Check if promo code is currently valid"""
        now = datetime.utcnow()
        return (
            self.is_active and
            self.valid_from <= now <= self.valid_until and
            (self.total_usage_limit is None or self.current_usage_count < self.total_usage_limit)
        )
    
    def calculate_discount(self, fare_amount: int) -> int:
        """Calculate discount amount for given fare"""
        if fare_amount < self.min_order_value:
            return 0
        
        if self.promo_type == PromoType.PERCENTAGE:
            discount = int(fare_amount * (self.discount_value / 100))
        elif self.promo_type == PromoType.FIXED:
            discount = int(self.discount_value)
        elif self.promo_type == PromoType.FREE_RIDE:
            discount = fare_amount
        else:
            discount = 0
        
        # Apply max discount cap if set
        if self.max_discount:
            discount = min(discount, self.max_discount)
        
        return min(discount, fare_amount)  # Don't exceed fare amount


class PromoUsage(BaseModel):
    """
    Track promo code usage per user.
    """
    __tablename__ = "promo_usages"
    
    promo_code_id: Mapped[int] = mapped_column(
        ForeignKey("promo_codes.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    
    user_id: Mapped[int] = mapped_column(
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    
    ride_id: Mapped[int] = mapped_column(
        ForeignKey("rides.id", ondelete="CASCADE"),
        nullable=False
    )
    
    # Discount applied
    discount_applied: Mapped[int] = mapped_column(Integer, nullable=False)  # In cents
    original_fare: Mapped[int] = mapped_column(Integer, nullable=False)
    final_fare: Mapped[int] = mapped_column(Integer, nullable=False)
    
    # Relationships
    promo_code: Mapped["PromoCode"] = relationship(
        "PromoCode",
        back_populates="usages"
    )
    
    # Indexes
    __table_args__ = (
        Index('idx_promo_usage_user', 'promo_code_id', 'user_id'),
    )
