"""
Admin Routes
Dashboard, user management, driver verification, and reporting
"""
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.driver import Driver, DriverStatus
from app.models.ride import Ride, RideStatus
from app.models.payment import WithdrawalRequest, WithdrawalStatus
from app.schemas.user import UserListResponse, UserBlockRequest
from app.schemas.driver import DriverResponse, DriverVerificationRequest
from app.schemas.config import AdminDashboardResponse, PromoCodeCreate, PromoCodeResponse
from app.schemas.payment import WithdrawalResponse
from app.schemas.ride import RideListResponse
from app.schemas.common import MessageResponse, PaginatedResponse
from app.services.config_service import ConfigService
from app.services.payment_service import PaymentService
from app.utils.dependencies import get_current_user, require_role, require_admin
from app.utils.helpers import build_order_by

router = APIRouter()


@router.get("/dashboard", response_model=AdminDashboardResponse)
async def get_dashboard(
    current_user: User = Depends(require_admin),
    db: AsyncSession = Depends(get_db)
):
    """Get admin dashboard statistics"""
    stats = await ConfigService.get_dashboard_stats(db)
    return AdminDashboardResponse(**stats)


# User Management

@router.get("/users", response_model=PaginatedResponse[UserListResponse])
async def list_users(
    role: Optional[UserRole] = None,
    is_active: Optional[bool] = None,
    search: Optional[str] = None,
    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_admin),
    db: AsyncSession = Depends(get_db)
):
    """List all users with filters"""
    query = select(User)
    count_query = select(func.count(User.id))
    if role:
        query = query.where(User.role == role)
        count_query = count_query.where(User.role == role)
    if is_active is not None:
        query = query.where(User.is_active == is_active)
        count_query = count_query.where(User.is_active == is_active)
    if search:
        search_filter = User.email.contains(search) | User.phone.contains(search) | User.first_name.contains(search)
        query = query.where(search_filter)
        count_query = count_query.where(search_filter)

    count_result = await db.execute(count_query)
    total = count_result.scalar() or 0

    offset = (page - 1) * limit
    order_clause = build_order_by(User, sort_by, order, {"created_at", "updated_at", "email", "first_name", "last_name"})
    query = query.order_by(order_clause).offset(offset).limit(limit)
    result = await db.execute(query)
    users = result.scalars().all()
    items = [UserListResponse.model_validate(u) for u in users]
    
    return PaginatedResponse.create(items, total, page, limit)


@router.get("/users/{user_id}", response_model=UserListResponse)
async def get_user(
    user_id: int,
    current_user: User = Depends(require_admin),
    db: AsyncSession = Depends(get_db)
):
    """Get user details by ID"""
    query = select(User).where(User.id == user_id).options(
        selectinload(User.driver_profile),
        selectinload(User.wallet)
    )
    result = await db.execute(query)
    user = result.scalar_one_or_none()
    
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    
    return UserListResponse.model_validate(user)


@router.put("/users/{user_id}/block", response_model=MessageResponse)
async def block_user(
    user_id: int,
    data: UserBlockRequest,
    current_user: User = Depends(require_admin),
    db: AsyncSession = Depends(get_db)
):
    """Block or unblock a user"""
    query = select(User).where(User.id == user_id)
    result = await db.execute(query)
    user = result.scalar_one_or_none()
    
    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
    
    user.is_blocked = data.is_blocked
    user.blocked_reason = data.reason if data.is_blocked else None
    
    await db.commit()
    
    action = "blocked" if data.is_blocked else "unblocked"
    return MessageResponse(message=f"User {action} successfully")


# Driver Verification

@router.get("/drivers/pending", response_model=PaginatedResponse[DriverResponse])
async def get_pending_drivers(
    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_admin),
    db: AsyncSession = Depends(get_db)
):
    """Get drivers pending verification"""
    status_filter = Driver.status.in_([DriverStatus.PENDING, DriverStatus.UNDER_REVIEW])
    count_result = await db.execute(select(func.count(Driver.id)).where(status_filter))
    total = count_result.scalar() or 0

    base_query = select(Driver).where(status_filter)
    
    offset = (page - 1) * limit
    order_clause = build_order_by(Driver, sort_by, order, {"created_at", "updated_at", "id"})
    # Driver.documents has lazy="dynamic" - selectinload not supported. DriverResponse does not use documents.
    query = base_query.options(selectinload(Driver.user)).order_by(order_clause).offset(offset).limit(limit)
    result = await db.execute(query)
    drivers = result.scalars().all()
    items = [
        DriverResponse(
            id=d.id,
            user_id=d.user_id,
            full_name=d.user.full_name,
            email=d.user.email,
            phone=d.user.phone,
            profile_picture=d.user.profile_picture,
            license_number=d.license_number,
            license_expiry=d.license_expiry,
            status=d.status,
            is_online=d.is_online,
            is_on_ride=d.is_on_ride,
            average_rating=d.average_rating,
            total_ratings=d.total_ratings,
            total_rides=d.total_rides,
            completed_rides=d.completed_rides,
            total_earnings=d.total_earnings,
            current_balance=d.current_balance,
            created_at=d.created_at
        )
        for d in drivers
    ]
    
    return PaginatedResponse.create(items, total, page, limit)


@router.put("/drivers/{driver_id}/verify", response_model=MessageResponse)
async def verify_driver(
    driver_id: int,
    data: DriverVerificationRequest,
    current_user: User = Depends(require_admin),
    db: AsyncSession = Depends(get_db)
):
    """Approve or reject driver verification"""
    from datetime import datetime
    
    query = select(Driver).where(Driver.id == driver_id)
    result = await db.execute(query)
    driver = result.scalar_one_or_none()
    
    if not driver:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Driver not found")
    
    driver.status = data.status
    driver.verified_by = current_user.id
    driver.verified_at = datetime.utcnow()
    
    if data.status == DriverStatus.REJECTED:
        driver.rejection_reason = data.rejection_reason
    
    await db.commit()
    
    # TODO: Send notification to driver
    
    return MessageResponse(message=f"Driver {data.status.value}")


# Withdrawal Management

@router.get("/withdrawals/pending", response_model=PaginatedResponse[WithdrawalResponse])
async def get_pending_withdrawals(
    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_admin),
    db: AsyncSession = Depends(get_db)
):
    """Get pending withdrawal requests"""
    status_filter = WithdrawalRequest.status == WithdrawalStatus.PENDING
    count_result = await db.execute(select(func.count(WithdrawalRequest.id)).where(status_filter))
    total = count_result.scalar() or 0

    offset = (page - 1) * limit
    order_clause = build_order_by(WithdrawalRequest, sort_by, order, {"created_at", "updated_at", "amount", "id"})
    query = select(WithdrawalRequest).where(status_filter).order_by(order_clause).offset(offset).limit(limit)
    result = await db.execute(query)
    withdrawals = result.scalars().all()
    items = [WithdrawalResponse.model_validate(w) for w in withdrawals]
    
    return PaginatedResponse.create(items, total, page, limit)


@router.put("/withdrawals/{withdrawal_id}/process", response_model=MessageResponse)
async def process_withdrawal(
    withdrawal_id: int,
    approve: bool,
    rejection_reason: Optional[str] = None,
    current_user: User = Depends(require_admin),
    db: AsyncSession = Depends(get_db)
):
    """Approve or reject withdrawal request"""
    try:
        await PaymentService.process_withdrawal(
            db, withdrawal_id, current_user.id, approve, rejection_reason
        )
        action = "approved" if approve else "rejected"
        return MessageResponse(message=f"Withdrawal {action}")
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))


# Promo Codes

@router.post("/promo-codes", response_model=PromoCodeResponse)
async def create_promo_code(
    data: PromoCodeCreate,
    current_user: User = Depends(require_admin),
    db: AsyncSession = Depends(get_db)
):
    """Create a new promo code"""
    from app.models.promo import PromoCode, PromoType
    
    # Check if code already exists
    existing = await db.execute(
        select(PromoCode).where(PromoCode.code == data.code.upper())
    )
    if existing.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Promo code already exists"
        )
    
    promo = PromoCode(
        code=data.code.upper(),
        title=data.title,
        description=data.description,
        promo_type=PromoType(data.promo_type),
        discount_value=data.discount_value,
        min_order_value=data.min_order_value,
        max_discount=data.max_discount,
        total_usage_limit=data.total_usage_limit,
        per_user_limit=data.per_user_limit,
        valid_from=data.valid_from,
        valid_until=data.valid_until,
        for_new_users_only=data.for_new_users_only,
        is_active=data.is_active,
        created_by=current_user.id
    )
    
    db.add(promo)
    await db.commit()
    await db.refresh(promo)
    
    return PromoCodeResponse.model_validate(promo)


@router.get("/promo-codes", response_model=PaginatedResponse[PromoCodeResponse])
async def list_promo_codes(
    active_only: bool = False,
    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_admin),
    db: AsyncSession = Depends(get_db)
):
    """List all promo codes"""
    from app.models.promo import PromoCode
    
    query = select(PromoCode)
    count_query = select(func.count(PromoCode.id))
    if active_only:
        query = query.where(PromoCode.is_active == True)
        count_query = count_query.where(PromoCode.is_active == True)

    count_result = await db.execute(count_query)
    total = count_result.scalar() or 0

    offset = (page - 1) * limit
    order_clause = build_order_by(PromoCode, sort_by, order, {"created_at", "updated_at", "code", "id"})
    query = query.order_by(order_clause).offset(offset).limit(limit)
    result = await db.execute(query)
    promos = result.scalars().all()
    items = [PromoCodeResponse.model_validate(p) for p in promos]
    
    return PaginatedResponse.create(items, total, page, limit)


# Live Rides

@router.get("/rides/live", response_model=PaginatedResponse[RideListResponse])
async def get_live_rides(
    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_admin),
    db: AsyncSession = Depends(get_db)
):
    """Get all currently active rides"""
    status_filter = Ride.status.in_([
        RideStatus.ACCEPTED,
        RideStatus.DRIVER_ARRIVED,
        RideStatus.STARTED
    ])
    count_result = await db.execute(select(func.count(Ride.id)).where(status_filter))
    total = count_result.scalar() or 0

    offset = (page - 1) * limit
    order_clause = build_order_by(Ride, sort_by, order, {"created_at", "updated_at", "requested_at", "id"})
    # Driver.user must be eagerly loaded to avoid lazy-load in async context (MissingGreenlet)
    query = select(Ride).where(status_filter).options(
        selectinload(Ride.passenger),
        selectinload(Ride.driver).selectinload(Driver.user),
        selectinload(Ride.vehicle_category),
        selectinload(Ride.rating)
    ).order_by(order_clause).offset(offset).limit(limit)
    result = await db.execute(query)
    rides = result.scalars().all()
    items = [
        RideListResponse(
            id=ride.id,
            ride_code=ride.ride_code,
            status=ride.status,
            pickup_address=ride.pickup_address,
            dropoff_address=ride.dropoff_address,
            estimated_fare=ride.estimated_fare,
            final_fare=ride.final_fare,
            payment_method=ride.payment_method,
            vehicle_category_name=ride.vehicle_category.display_name if ride.vehicle_category else "",
            driver_name=ride.driver.user.full_name if ride.driver else None,
            driver_rating=ride.driver.average_rating if ride.driver else None,
            rating_given=ride.rating.driver_rating if ride.rating else None,
            requested_at=ride.requested_at,
            completed_at=ride.completed_at
        )
        for ride in rides
    ]
    
    return PaginatedResponse.create(items, total, page, limit)
