from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import func as sql_func
from datetime import datetime
from typing import List
from ..database import get_db
from ..models import User, WithdrawalRequest, DealerInfo, ShareReward, ReferralReward
from ..schemas import (
    WithdrawalRequestCreate, WithdrawalRequestResponse,
    WithdrawalProcess, WithdrawalBalance,
)
from .auth import get_current_user
from .notification import notify_withdrawal_processed

router = APIRouter(prefix="/withdrawal", tags=["withdrawal"])

# Tax rate (3.3% withholding)
TAX_RATE = 0.033


def calculate_user_balance(user: User, db: Session) -> WithdrawalBalance:
    """Calculate user's withdrawal balance from all sources"""
    total_earned = 0.0
    total_withdrawn = 0.0
    pending_withdrawal = 0.0

    # Get dealer earnings if user is a dealer
    if user.is_dealer:
        dealer_info = db.query(DealerInfo).filter(DealerInfo.user_id == user.id).first()
        if dealer_info:
            total_earned += dealer_info.total_commission_earned
            total_withdrawn += dealer_info.total_withdrawn

    # Get share rewards
    share_rewards = db.query(ShareReward).filter(
        ShareReward.user_id == user.id,
        ShareReward.status.in_(["approved", "withdrawn"])
    ).all()

    for reward in share_rewards:
        total_earned += reward.net_amount
        if reward.status == "withdrawn":
            total_withdrawn += reward.net_amount

    # Get referral rewards
    referral_rewards = db.query(ReferralReward).filter(
        ReferralReward.referrer_id == user.id,
        ReferralReward.status.in_(["credited", "withdrawn"])
    ).all()

    for reward in referral_rewards:
        total_earned += reward.reward_amount
        if reward.status == "withdrawn":
            total_withdrawn += reward.reward_amount

    # Get pending withdrawals
    pending_requests = db.query(WithdrawalRequest).filter(
        WithdrawalRequest.user_id == user.id,
        WithdrawalRequest.status.in_(["pending", "approved"])
    ).all()

    for req in pending_requests:
        pending_withdrawal += req.net_amount

    available_balance = total_earned - total_withdrawn - pending_withdrawal

    return WithdrawalBalance(
        total_earned=total_earned,
        total_withdrawn=total_withdrawn,
        pending_withdrawal=pending_withdrawal,
        available_balance=max(0, available_balance)
    )


@router.get("/balance", response_model=WithdrawalBalance)
def get_balance(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Get current user's withdrawal balance"""
    return calculate_user_balance(current_user, db)


@router.post("/request", response_model=WithdrawalRequestResponse)
def create_withdrawal_request(
    request_data: WithdrawalRequestCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Create a new withdrawal request"""
    # Check balance
    balance = calculate_user_balance(current_user, db)

    if request_data.amount <= 0:
        raise HTTPException(status_code=400, detail="Amount must be positive")

    if request_data.amount > balance.available_balance:
        raise HTTPException(
            status_code=400,
            detail=f"Insufficient balance. Available: {balance.available_balance}"
        )

    # Minimum withdrawal amount
    MIN_WITHDRAWAL = 10  # 10 USD minimum
    if request_data.amount < MIN_WITHDRAWAL:
        raise HTTPException(
            status_code=400,
            detail=f"Minimum withdrawal amount is ${MIN_WITHDRAWAL} USD"
        )

    # Calculate tax and net amount
    tax_amount = request_data.amount * TAX_RATE
    net_amount = request_data.amount - tax_amount

    # Create withdrawal request
    withdrawal = WithdrawalRequest(
        user_id=current_user.id,
        amount=request_data.amount,
        tax_withheld=tax_amount,
        net_amount=net_amount,
        bank_name=request_data.bank_name,
        bank_account=request_data.bank_account,
        account_holder=request_data.account_holder,
        status="pending"
    )

    db.add(withdrawal)
    db.commit()
    db.refresh(withdrawal)

    return withdrawal


@router.get("/my-requests", response_model=List[WithdrawalRequestResponse])
def get_my_requests(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Get current user's withdrawal requests"""
    requests = db.query(WithdrawalRequest).filter(
        WithdrawalRequest.user_id == current_user.id
    ).order_by(WithdrawalRequest.requested_at.desc()).all()

    return requests


# Admin endpoints
@router.get("/admin/list", response_model=List[WithdrawalRequestResponse])
def get_all_requests(
    status_filter: str = None,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """[Admin] Get all withdrawal requests"""
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Admin access required")

    query = db.query(WithdrawalRequest)
    if status_filter:
        query = query.filter(WithdrawalRequest.status == status_filter)

    requests = query.order_by(WithdrawalRequest.requested_at.desc()).all()
    return requests


@router.put("/admin/{request_id}/process", response_model=WithdrawalRequestResponse)
def process_withdrawal(
    request_id: int,
    process_data: WithdrawalProcess,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """[Admin] Process a withdrawal request"""
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Admin access required")

    withdrawal = db.query(WithdrawalRequest).filter(
        WithdrawalRequest.id == request_id
    ).first()

    if not withdrawal:
        raise HTTPException(status_code=404, detail="Request not found")

    valid_statuses = ["approved", "completed", "rejected"]
    if process_data.status not in valid_statuses:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid status. Must be one of: {valid_statuses}"
        )

    # Update status
    withdrawal.status = process_data.status
    withdrawal.admin_note = process_data.admin_note
    withdrawal.processed_at = datetime.utcnow()

    # If completed, update user's withdrawal totals
    if process_data.status == "completed":
        user = db.query(User).filter(User.id == withdrawal.user_id).first()

        # Update dealer info if applicable
        if user.is_dealer:
            dealer_info = db.query(DealerInfo).filter(
                DealerInfo.user_id == user.id
            ).first()
            if dealer_info:
                dealer_info.total_withdrawn += withdrawal.net_amount

        # Mark related share rewards as withdrawn
        # (This is a simplified version - in production you'd track which specific rewards were withdrawn)

    db.commit()
    db.refresh(withdrawal)

    # Send notification to user about withdrawal status
    notify_withdrawal_processed(db, withdrawal.user_id, withdrawal.id, process_data.status, withdrawal.net_amount)

    return withdrawal
