from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from datetime import datetime, timedelta
from jose import JWTError, jwt
from pydantic import BaseModel
from typing import Optional
import bcrypt
from ..database import get_db
from ..models import User
from ..models.user import generate_referral_code
from ..schemas import UserCreate, UserUpdate, UserResponse, Token
from ..config import get_settings

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

settings = get_settings()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")


def verify_password(plain_password: str, hashed_password: str) -> bool:
    return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password.encode('utf-8'))


def get_password_hash(password: str) -> str:
    return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')


def create_access_token(data: dict) -> str:
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)


def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: Session = Depends(get_db)
) -> User:
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        email: str = payload.get("sub")
        if email is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception

    user = db.query(User).filter(User.email == email).first()
    if user is None:
        raise credentials_exception
    return user


# Optional 인증 scheme
oauth2_scheme_optional = OAuth2PasswordBearer(tokenUrl="/api/auth/login", auto_error=False)


def get_current_user_optional(
    token: str = Depends(oauth2_scheme_optional),
    db: Session = Depends(get_db)
) -> User | None:
    """선택적 인증 - 토큰이 없거나 유효하지 않아도 None 반환"""
    if not token:
        return None
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        email: str = payload.get("sub")
        if email is None:
            return None
    except JWTError:
        return None

    user = db.query(User).filter(User.email == email).first()
    return user


def get_current_admin_user(
    current_user: User = Depends(get_current_user)
) -> User:
    """관리자 권한 확인"""
    if not current_user.is_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Admin access required"
        )
    return current_user


@router.post("/register", response_model=UserResponse)
def register(user_data: UserCreate, db: Session = Depends(get_db)):
    """회원가입"""
    from ..models.user import VerificationCode
    from datetime import datetime

    existing = db.query(User).filter(User.email == user_data.email).first()
    if existing:
        raise HTTPException(status_code=400, detail="Email already registered")

    # Check if email was verified (pre-registration verification)
    email_verified = False
    verification = db.query(VerificationCode).filter(
        VerificationCode.email == user_data.email,
        VerificationCode.code_type == "email",
        VerificationCode.verified_at.isnot(None)
    ).order_by(VerificationCode.verified_at.desc()).first()

    if verification:
        email_verified = True

    # Generate unique referral code
    referral_code = generate_referral_code()
    while db.query(User).filter(User.referral_code == referral_code).first():
        referral_code = generate_referral_code()

    user = User(
        email=user_data.email,
        password_hash=get_password_hash(user_data.password),
        name=user_data.name,
        phone=user_data.phone,
        country=user_data.country,
        referral_code=referral_code,
        referred_by=getattr(user_data, 'referred_by', None),
        email_verified=email_verified,
        email_verified_at=datetime.utcnow() if email_verified else None,
    )
    db.add(user)
    db.commit()
    db.refresh(user)
    return user


@router.post("/login", response_model=Token)
def login(
    form_data: OAuth2PasswordRequestForm = Depends(),
    db: Session = Depends(get_db)
):
    """로그인"""
    user = db.query(User).filter(User.email == form_data.username).first()
    if not user or not verify_password(form_data.password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect email or password",
            headers={"WWW-Authenticate": "Bearer"},
        )

    access_token = create_access_token(data={"sub": user.email})
    return Token(access_token=access_token)


@router.get("/me", response_model=UserResponse)
def get_me(current_user: User = Depends(get_current_user)):
    """현재 사용자 정보"""
    return current_user


@router.put("/me", response_model=UserResponse)
def update_me(
    user_update: UserUpdate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """사용자 정보 수정"""
    if user_update.name is not None:
        current_user.name = user_update.name
    if user_update.phone is not None:
        current_user.phone = user_update.phone
    if user_update.country is not None:
        current_user.country = user_update.country

    db.commit()
    db.refresh(current_user)
    return current_user


# Admin User Management Endpoints
@router.get("/admin/users")
def admin_get_users(
    page: int = 1,
    page_size: int = 20,
    search: str = None,
    is_dealer: bool = None,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """모든 사용자 목록 조회 (관리자) - 삭제된 사용자 제외"""
    query = db.query(User).filter(
        User.is_admin == False,
        User.deleted_at.is_(None)  # 삭제되지 않은 사용자만
    )

    if search:
        query = query.filter(
            (User.email.ilike(f"%{search}%")) |
            (User.name.ilike(f"%{search}%")) |
            (User.phone.ilike(f"%{search}%"))
        )

    if is_dealer is not None:
        query = query.filter(User.is_dealer == is_dealer)

    total = query.count()
    users = query.order_by(User.created_at.desc()).offset((page - 1) * page_size).limit(page_size).all()

    return {
        "users": [
            {
                "id": user.id,
                "email": user.email,
                "name": user.name,
                "phone": user.phone,
                "country": user.country,
                "cc_balance": user.cc_balance,
                "is_dealer": user.is_dealer,
                "referral_code": user.referral_code,
                "referred_by": user.referred_by,
                "created_at": user.created_at.isoformat() if user.created_at else None,
            }
            for user in users
        ],
        "total": total,
        "page": page,
        "page_size": page_size
    }


@router.get("/admin/users/{user_id}")
def admin_get_user(
    user_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """특정 사용자 상세 정보 (관리자)"""
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    return {
        "id": user.id,
        "email": user.email,
        "name": user.name,
        "phone": user.phone,
        "country": user.country,
        "cc_balance": user.cc_balance,
        "is_admin": user.is_admin,
        "is_dealer": user.is_dealer,
        "referral_code": user.referral_code,
        "referred_by": user.referred_by,
        "created_at": user.created_at.isoformat() if user.created_at else None,
    }


@router.put("/admin/users/{user_id}")
def admin_update_user(
    user_id: int,
    user_update: UserUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """사용자 정보 수정 (관리자)"""
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    if user_update.name is not None:
        user.name = user_update.name
    if user_update.phone is not None:
        user.phone = user_update.phone
    if user_update.country is not None:
        user.country = user_update.country

    db.commit()
    db.refresh(user)

    return {
        "id": user.id,
        "email": user.email,
        "name": user.name,
        "phone": user.phone,
        "country": user.country,
        "cc_balance": user.cc_balance,
        "is_dealer": user.is_dealer,
        "created_at": user.created_at.isoformat() if user.created_at else None,
    }


@router.put("/admin/users/{user_id}/cc")
def admin_adjust_cc(
    user_id: int,
    amount: float,
    reason: str = "Admin adjustment",
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """사용자 CC 잔액 조정 (관리자)"""
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    user.cc_balance = user.cc_balance + amount
    if user.cc_balance < 0:
        user.cc_balance = 0

    db.commit()
    db.refresh(user)

    return {
        "message": f"CC balance adjusted by {amount}",
        "new_balance": user.cc_balance
    }


# ===== 사용자 탈퇴 =====

class WithdrawalRequest(BaseModel):
    """탈퇴 요청"""
    reason: Optional[str] = None
    password: str  # 본인 확인용


@router.post("/withdraw")
def request_withdrawal(
    request: WithdrawalRequest,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """사용자 탈퇴 요청"""
    # 비밀번호 확인
    if not verify_password(request.password, current_user.password_hash):
        raise HTTPException(status_code=400, detail="Incorrect password")

    # 이미 탈퇴 요청한 경우
    if current_user.withdrawal_requested_at:
        raise HTTPException(status_code=400, detail="Withdrawal already requested")

    # 관리자는 탈퇴 불가
    if current_user.is_admin:
        raise HTTPException(status_code=400, detail="Admin cannot withdraw")

    # 탈퇴 요청 기록
    current_user.withdrawal_requested_at = datetime.utcnow()
    current_user.withdrawal_reason = request.reason
    current_user.is_active = False  # 계정 비활성화

    db.commit()

    return {
        "message": "Withdrawal request submitted. Your account has been deactivated.",
        "withdrawal_requested_at": current_user.withdrawal_requested_at.isoformat()
    }


@router.post("/withdraw/cancel")
def cancel_withdrawal(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """탈퇴 요청 취소 (아직 삭제되지 않은 경우)"""
    if not current_user.withdrawal_requested_at:
        raise HTTPException(status_code=400, detail="No withdrawal request found")

    if current_user.deleted_at:
        raise HTTPException(status_code=400, detail="Account already deleted")

    # 탈퇴 요청 취소
    current_user.withdrawal_requested_at = None
    current_user.withdrawal_reason = None
    current_user.is_active = True

    db.commit()

    return {"message": "Withdrawal request cancelled. Your account is active again."}


# ===== 관리자 사용자 삭제 =====

@router.delete("/admin/users/{user_id}")
def admin_delete_user(
    user_id: int,
    hard_delete: bool = False,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """사용자 삭제 (관리자 전용)
    - hard_delete=False: 소프트 삭제 (deleted_at 설정)
    - hard_delete=True: 완전 삭제 (DB에서 제거)
    """
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    # 관리자는 삭제 불가
    if user.is_admin:
        raise HTTPException(status_code=400, detail="Cannot delete admin user")

    # 자기 자신은 삭제 불가
    if user.id == current_user.id:
        raise HTTPException(status_code=400, detail="Cannot delete yourself")

    user_email = user.email

    if hard_delete:
        # 완전 삭제 - 관련 데이터도 함께 삭제
        from ..models import CarView, PerformanceCheckView, ChargeHistory, Inquiry, Notification

        db.query(CarView).filter(CarView.user_id == user_id).delete()
        db.query(PerformanceCheckView).filter(PerformanceCheckView.user_id == user_id).delete()
        db.query(ChargeHistory).filter(ChargeHistory.user_id == user_id).delete()
        db.query(Inquiry).filter(Inquiry.user_id == user_id).delete()
        db.query(Notification).filter(Notification.user_id == user_id).delete()
        db.delete(user)
        db.commit()

        return {
            "message": f"User {user_email} permanently deleted",
            "deleted_user_id": user_id,
            "hard_delete": True
        }
    else:
        # 소프트 삭제
        user.deleted_at = datetime.utcnow()
        user.is_active = False
        db.commit()

        return {
            "message": f"User {user_email} soft deleted",
            "deleted_user_id": user_id,
            "deleted_at": user.deleted_at.isoformat(),
            "hard_delete": False
        }


@router.get("/admin/users/withdrawn")
def admin_get_withdrawn_users(
    page: int = 1,
    page_size: int = 20,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """탈퇴 요청한 사용자 목록 (관리자)"""
    query = db.query(User).filter(
        User.withdrawal_requested_at.isnot(None),
        User.deleted_at.is_(None)  # 아직 삭제되지 않은 사용자만
    )

    total = query.count()
    users = query.order_by(User.withdrawal_requested_at.desc()).offset((page - 1) * page_size).limit(page_size).all()

    return {
        "users": [
            {
                "id": user.id,
                "email": user.email,
                "name": user.name,
                "phone": user.phone,
                "country": user.country,
                "cc_balance": user.cc_balance,
                "is_dealer": user.is_dealer,
                "withdrawal_requested_at": user.withdrawal_requested_at.isoformat() if user.withdrawal_requested_at else None,
                "withdrawal_reason": user.withdrawal_reason,
                "created_at": user.created_at.isoformat() if user.created_at else None,
            }
            for user in users
        ],
        "total": total,
        "page": page,
        "page_size": page_size
    }


@router.get("/admin/users/deleted")
def admin_get_deleted_users(
    page: int = 1,
    page_size: int = 20,
    search: str = None,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """삭제된 사용자 목록 (관리자)"""
    query = db.query(User).filter(
        User.deleted_at.isnot(None)  # 삭제된 사용자만
    )

    if search:
        query = query.filter(
            (User.email.ilike(f"%{search}%")) |
            (User.name.ilike(f"%{search}%")) |
            (User.phone.ilike(f"%{search}%"))
        )

    total = query.count()
    users = query.order_by(User.deleted_at.desc()).offset((page - 1) * page_size).limit(page_size).all()

    return {
        "users": [
            {
                "id": user.id,
                "email": user.email,
                "name": user.name,
                "phone": user.phone,
                "country": user.country,
                "cc_balance": user.cc_balance,
                "is_dealer": user.is_dealer,
                "referral_code": user.referral_code,
                "referred_by": user.referred_by,
                "deleted_at": user.deleted_at.isoformat() if user.deleted_at else None,
                "withdrawal_reason": user.withdrawal_reason,
                "created_at": user.created_at.isoformat() if user.created_at else None,
            }
            for user in users
        ],
        "total": total,
        "page": page,
        "page_size": page_size
    }


@router.post("/admin/users/{user_id}/restore")
def admin_restore_user(
    user_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """삭제된 사용자 복원 (관리자)"""
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    if not user.deleted_at:
        raise HTTPException(status_code=400, detail="User is not deleted")

    user.deleted_at = None
    user.is_active = True
    user.withdrawal_requested_at = None
    user.withdrawal_reason = None

    db.commit()

    return {
        "message": f"User {user.email} restored successfully",
        "user_id": user_id
    }
