from fastapi import APIRouter, Depends, HTTPException, Query, status
from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session, aliased
from pydantic import BaseModel, EmailStr, Field
from datetime import datetime
from sqlalchemy.sql import func

from app.api.deps import get_db, get_current_user, get_current_admin_user
from app.models.user import User
from app.models.user_referral import UserReferral
from app.services import admin_service
from app.schemas.admin_setting import AdminSettingResponse, AdminSettingUpdate
import logging

router = APIRouter()

# Admin login request model
class AdminLoginRequest(BaseModel):
    username: str
    password: str

@router.post("/login")
def admin_login(
    login_data: AdminLoginRequest,
    db: Session = Depends(get_db)
) -> Any:
    """
    관리자 로그인 엔드포인트.
    
    일반 로그인과 동일하지만 관리자 사용자만 로그인 할 수 있습니다.
    
    Expected JSON body:
    {
        "username": "admin@example.com",
        "password": "admin_password"
    }
    """
    try:
        result = admin_service.authenticate_admin(
            db, 
            email=login_data.username, 
            password=login_data.password
        )
        
        if not result:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid admin credentials",
                headers={"WWW-Authenticate": "Bearer"},
            )
            
        
        logging.info(f"Successful admin login: {login_data.username}")
        return result
        
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Admin login failed: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=str(e)
        )

@router.get("/settings", response_model=List[AdminSettingResponse])
def get_all_settings(
    country_code: Optional[str] = Query(None, description="Filter settings by country code"),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """
    모든 관리자 설정을 조회합니다.
    country_code가 제공되면 해당 국가별 설정만 반환합니다.
    관리자 권한이 필요합니다.
    """
    return admin_service.get_all_settings(db, country_code)

@router.get("/settings/{setting_name}", response_model=AdminSettingResponse)
def get_setting(
    setting_name: str,
    country_code: Optional[str] = Query(None, description="Get setting for specific country"),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """
    특정 설정을 조회합니다.
    country_code가 제공되면 해당 국가별 설정을 조회합니다.
    관리자 권한이 필요합니다.
    """
    setting = admin_service.get_setting(db, setting_name, country_code)
    if not setting:
        # 설정이 없는 경우 기본값을 가진 응답 생성
        value = admin_service.get_setting_value(db, setting_name, country_code)
        raise HTTPException(
            status_code=404,
            detail=f"Setting '{setting_name}' not found. Default value: {value}"
        )
    return setting

@router.put("/settings/{setting_name}", response_model=AdminSettingResponse)
def update_setting(
    setting_name: str,
    setting_data: AdminSettingUpdate,
    country_code: Optional[str] = Query(None, description="Update setting for specific country"),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """
    설정을 업데이트합니다.
    country_code가 제공되면 해당 국가별 설정을 업데이트합니다.
    설정이 없는 경우 새로 생성합니다.
    관리자 권한이 필요합니다.
    """
    return admin_service.update_setting(db, setting_name, setting_data, country_code)

@router.get("/settings/default")
def create_default_settings(
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_admin_user)
):
    """
    기본 설정 값을 생성합니다. 이미 존재하는 설정은 변경하지 않습니다.
    관리자 권한이 필요합니다.
    """
    admin_service.ensure_default_settings(db)
    return {"message": "Default settings created successfully"}

# 유저 포인트 응답 스키마
class UserPointsInfo(BaseModel):
    user_id: int
    email: str
    first_name: str
    last_name: str
    total_points: int
    updated_at: datetime

@router.get("/user-points", response_model=List[UserPointsInfo])
def get_all_user_points(
    db: Session = Depends(get_db)
):
    """
    모든 사용자의 포인트 정보를 조회합니다.
    
    로그인 여부와 관계없이 접근 가능합니다.
    """
    try:
        user_points = admin_service.get_all_user_points(db)
        return user_points
    except Exception as e:
        logging.error(f"Failed to retrieve user points: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"포인트 정보 조회 중 오류가 발생했습니다: {str(e)}"
        )

# 관리자용 사용자 정보 업데이트 스키마
class AdminUserUpdate(BaseModel):
    first_name: str = Field(..., min_length=2, max_length=50)
    last_name: str = Field(..., min_length=2, max_length=50)
    email: EmailStr
    phone_code: str = Field(..., pattern=r'^\+?[0-9]{1,4}$')
    phone: str = Field(..., pattern=r'^[0-9]{10,15}$')
    gender: str = Field(..., pattern=r'^[MF]$')  # M for Male, F for Female
    birth_date: str = Field(..., pattern=r'^\d{4}-\d{2}-\d{2}$')
    daily_step_goal: int = Field(..., ge=1000, le=100000)
    status: int = Field(..., ge=0, le=1)  # 0: Inactive, 1: Active

# 사용자 정보 업데이트 응답 스키마
class AdminUserUpdateResponse(BaseModel):
    id: int
    email: str
    first_name: str
    last_name: str
    phone_code: str
    phone: str
    gender: str
    birth_date: str
    daily_step_goal: int
    status: int
    updated_at: datetime

@router.put("/users/{user_id}", response_model=AdminUserUpdateResponse)
def update_user_by_admin(
    user_id: int,
    user_data: AdminUserUpdate,
    db: Session = Depends(get_db)
):
    """
    관리자 권한으로 사용자 정보를 업데이트합니다.
    
    로그인 여부와 관계없이 접근 가능합니다.
    """
    try:
        # 요청 데이터를 딕셔너리로 변환
        user_data_dict = user_data.dict()
        
        # 사용자 정보 업데이트
        updated_user = admin_service.update_user_by_admin(db, user_id, user_data_dict)
        return updated_user
    except HTTPException:
        raise
    except Exception as e:
        logging.error(f"Failed to update user: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"사용자 정보 업데이트 중 오류가 발생했습니다: {str(e)}"
        )
    
@router.delete("/product-categories/{category_id}", response_model=Dict[str, Any])
def delete_product_category_endpoint(
    category_id: int,
    db: Session = Depends(get_db)
):
    """
    관리자 권한으로 상품 카테고리를 삭제하는 엔드포인트입니다.
    
    로그인 여부와 관계없이 접근 가능합니다.
    
    제약 조건:
    - 카테고리에 속한 제품이 있는 경우 삭제할 수 없습니다.
    - 관련 제품을 먼저 제거하거나 다른 카테고리로 재할당해야 합니다.
    """
    try:
        result = admin_service.delete_product_category(db, category_id)
        return result
    except HTTPException:
        # 이미 처리된 HTTP 예외는 그대로 전달
        raise
    except Exception as e:
        logging.error(f"Error deleting product category: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"상품 카테고리 삭제 중 오류가 발생했습니다: {str(e)}"
        )

@router.get("/orders", response_model=List[Dict[str, Any]])
def get_all_orders_endpoint(
    skip: int = Query(0, description="건너뛸 레코드 수"),
    limit: int = Query(100, description="최대 조회 레코드 수"),
    db: Session = Depends(get_db)
):
    """
    관리자용 모든 사용자의 주문정보를 조회합니다.
    
    Args:
        skip (int): 건너뛸 레코드 수
        limit (int): 조회할 최대 레코드 수
        db (Session): 데이터베이스 세션
        
    Returns:
        List[Dict]: 모든 주문 정보 목록
    """
    return admin_service.get_all_orders(db, skip, limit)

class OrderStatusUpdate(BaseModel):
    status: str = Field(..., description="주문 상태 (DELIVERED, PROCESSING, PENDING, CANCELLED)")

@router.put("/orders/{order_id}/status", response_model=Dict[str, Any])
def update_order_status_endpoint(
    order_id: int,
    status_update: OrderStatusUpdate,
    db: Session = Depends(get_db)
):
    """
    주문 상태를 업데이트합니다.
    
    Args:
        order_id (int): 업데이트할 주문 ID
        status_update (OrderStatusUpdate): 업데이트할 상태 정보
        db (Session): 데이터베이스 세션
        
    Returns:
        Dict[str, Any]: 업데이트된 주문 정보
    """
    return admin_service.update_order_status(db, order_id, status_update.status)

# 광고 추가/수정 요청 모델
class AdvertisementRequest(BaseModel):
    ad_url: str = Field(..., description="광고 URL")
    video_list_order: int = Field(..., description="광고 비디오 나열 순서", ge=1)
    ad_video_points: int = Field(..., description="광고 비디오 시청 시 지급되는 포인트", ge=0)

@router.post("/advertisements", response_model=Dict[str, Any])
def create_advertisement_endpoint(
    ad_data: AdvertisementRequest,
    db: Session = Depends(get_db)
):
    """
    새로운 광고를 추가합니다.
    
    Args:
        ad_data (AdvertisementRequest): 광고 정보 (ad_url, video_list_order, ad_video_points)
        db (Session): 데이터베이스 세션
        
    Returns:
        Dict[str, Any]: 생성된 광고 정보
    """
    return admin_service.create_advertisement(db, ad_data.dict())

@router.delete("/advertisements/{ad_id}", response_model=Dict[str, Any])
def delete_advertisement_endpoint(
    ad_id: int,
    db: Session = Depends(get_db)
):
    """
    광고를 삭제합니다.
    
    Args:
        ad_id (int): 삭제할 광고 ID
        db (Session): 데이터베이스 세션
        
    Returns:
        Dict[str, Any]: 삭제 결과 메시지
    """
    return admin_service.delete_advertisement(db, ad_id)

# 레퍼럴 관계 생성 요청 스키마
class CreateReferralRequest(BaseModel):
    referrer_id: Optional[int] = None
    referrer_email: Optional[EmailStr] = None
    referred_id: Optional[int] = None
    referred_email: Optional[EmailStr] = None
    bonus_points: Optional[int] = Field(None, ge=0)

# 레퍼럴 사용자 정보 응답 스키마
class ReferralUserInfo(BaseModel):
    user_id: int
    email: str
    first_name: str
    last_name: str
    reference_code: str
    reference_code_used: Optional[str]
    referrer_id: Optional[int]
    referrer_email: Optional[str]
    referrer_name: Optional[str]
    register_date: datetime

@router.get("/referral-users", response_model=List[Dict[str, Any]])
def get_users_with_referral(
    db: Session = Depends(get_db),
    skip: int = Query(0, description="Skip records"),
    limit: int = Query(100, description="Limit records")
):
    """
    추천인 코드를 사용하여 가입한 사용자 목록을 조회합니다.
    
    한 사용자가 여러 추천인으로부터 추천을 받은 경우, 모든 추천인 정보가 포함됩니다.
    
    Args:
        db: 데이터베이스 세션
        skip: 건너뛸 레코드 수
        limit: 조회할 최대 레코드 수
        
    Returns:
        List[Dict[str, Any]]: 추천인 코드를 사용하여 가입한 사용자 목록
    """
    try:
        from app.models.user_referral import UserReferral
        from sqlalchemy.orm import aliased
        from sqlalchemy import func
        from collections import defaultdict
        
        logging.info(f"Querying users with referrals - skip={skip}, limit={limit}")
        
        # 사용자 기본 정보 조회 (모든 사용자)
        base_users = (
            db.query(
                User.id,
                User.email,
                User.first_name,
                User.last_name,
                User.reference_code,
                User.reference_code_used,
                User.created_at
            )
            .order_by(User.created_at.desc())
            .offset(skip)
            .limit(limit)
            .all()
        )
        
        # 각 사용자의 ID 목록
        user_ids = [user.id for user in base_users]
        
        # 추천한 사용자와 추천받은 사용자 정보를 위한 별칭
        ReferredUser = aliased(User)
        
        # 실제 user_referrals 테이블 데이터에 맞게 조회 (referrer_user_id -> referred_user_id)
        # 이 사용자가 추천한 모든 사용자 목록 조회
        referral_info = (
            db.query(
                UserReferral.referrer_user_id,
                UserReferral.referred_user_id,
                UserReferral.referral_date,
                UserReferral.awarded,
                ReferredUser.id.label("referred_id"),
                ReferredUser.email.label("referred_email"),
                ReferredUser.first_name.label("referred_first_name"),
                ReferredUser.last_name.label("referred_last_name"),
                ReferredUser.reference_code.label("referred_code")
            )
            .join(
                ReferredUser,
                UserReferral.referred_user_id == ReferredUser.id
            )
            .filter(UserReferral.referrer_user_id.in_(user_ids))
            .all()
        )
        
        # 추천받은 사용자 정보를 추천한 사용자 ID별로 그룹화
        referred_dict = defaultdict(list)
        for info in referral_info:
            referred_dict[info.referrer_user_id].append({
                "referred_id": info.referred_id,
                "referred_email": info.referred_email,
                "referred_name": f"{info.referred_first_name} {info.referred_last_name}",
                "referred_code": info.referred_code
            })
        
        # 최종 응답 구성
        result = []
        for user in base_users:
            # 사용자 기본 정보
            user_data = {
                "user_id": user.id,
                "email": user.email,
                "first_name": user.first_name, 
                "last_name": user.last_name,
                "reference_code": user.reference_code,
                "reference_code_used": user.reference_code_used,
                "register_date": user.created_at.isoformat(),
                "referred_users": referred_dict.get(user.id, [])
            }
            
            result.append(user_data)
        
        logging.info(f"Found {len(result)} users")
        return result
        
    except Exception as e:
        logging.error(f"Error retrieving users with referral: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"추천인 코드 사용자 조회 중 오류가 발생했습니다: {str(e)}"
        )

@router.post("/create-referral", response_model=Dict[str, Any])
def create_referral_relationship(
    request: CreateReferralRequest,
    db: Session = Depends(get_db)
):
    """
    관리자가 수동으로 사용자 간 추천 관계를 생성합니다.
    
    사용자 ID 또는 이메일을 사용하여 추천인과 추천받은 사용자를 지정할 수 있습니다.
    선택적으로 보너스 포인트를 지정할 수 있으며, 지정하지 않으면 기본 설정값이 사용됩니다.
    
    Args:
        request: 추천 관계 생성 요청 데이터
        db: 데이터베이스 세션
        
    Returns:
        Dict: 생성된 추천 관계 정보
    """
    try:
        from app.models.user import User
        from app.models.user_referral import UserReferral
        from app.models.point_transaction import PointTransaction
        from app.models.user_points import UserPoints
        from app.services.admin_service import get_setting_int
        from app.services.notification_service import NotificationService
        from app.services import friendship_service
        
        # 추천인 조회 (ID 또는 이메일로)
        referrer = None
        if request.referrer_id:
            referrer = db.query(User).filter(User.id == request.referrer_id).first()
        elif request.referrer_email:
            referrer = db.query(User).filter(User.email == request.referrer_email).first()
        
        if not referrer:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="추천인 사용자를 찾을 수 없습니다."
            )
        
        # 추천받은 사용자 조회 (ID 또는 이메일로)
        referred = None
        if request.referred_id:
            referred = db.query(User).filter(User.id == request.referred_id).first()
        elif request.referred_email:
            referred = db.query(User).filter(User.email == request.referred_email).first()
        
        if not referred:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="추천받은 사용자를 찾을 수 없습니다."
            )
        
        # 이미 추천 관계가 있는지 확인
        existing_referral = db.query(UserReferral).filter(
            UserReferral.referrer_user_id == referrer.id,
            UserReferral.referred_user_id == referred.id
        ).first()
        
        if existing_referral:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="이미 두 사용자 간에 추천 관계가 존재합니다."
            )
        
        # 수정된 로직: 추천한 사용자(referrer)의 reference_code_used만 업데이트
        # 추천받은 사용자(referred)의 reference_code_used는 변경하지 않음
        referrer.reference_code_used = referred.reference_code
        
        # 추천 관계 생성 (단방향)
        referral = UserReferral(
            referrer_user_id=referrer.id,
            referred_user_id=referred.id,
            awarded=True  # 즉시 보상 지급 표시
        )
        db.add(referral)
        
        # 친구 관계 생성
        friendship_service.create_friendship(
            db, 
            user_id=referrer.id,
            friend_id=referred.id,
            status="accepted"
        )
        
        # 보너스 포인트 설정
        bonus_points = request.bonus_points
        if bonus_points is None:
            # 기본 설정값 사용
            country_code = referred.country_code
            bonus_points = get_setting_int(db, "REFERRAL_BONUS", country_code)
            if bonus_points <= 0:
                bonus_points = 100  # 기본값
        
        # 추천인에게 포인트 지급
        point_tx = PointTransaction(
            user_id=referrer.id,
            transaction_type="referral_bonus",
            amount=bonus_points,
            description=f"Admin-created referral bonus for user {referred.email}"
        )
        db.add(point_tx)
        
        referrer_points = db.query(UserPoints).filter(UserPoints.user_id == referrer.id).first()
        if referrer_points:
            referrer_points.total_points += bonus_points
        else:
            referrer_points = UserPoints(user_id=referrer.id, total_points=bonus_points)
            db.add(referrer_points)
        
        # 추천받은 사용자에게 포인트 지급
        point_tx_referred = PointTransaction(
            user_id=referred.id,
            transaction_type="referral_bonus",
            amount=bonus_points,
            description=f"Admin-created signup bonus for referred user"
        )
        db.add(point_tx_referred)
        
        referred_points = db.query(UserPoints).filter(UserPoints.user_id == referred.id).first()
        if referred_points:
            referred_points.total_points += bonus_points
        else:
            referred_points = UserPoints(user_id=referred.id, total_points=bonus_points)
            db.add(referred_points)
        
        # 추천인에게 알림 전송
        NotificationService.create_notification(
            db, 
            user_id=referrer.id, 
            notif_type="award_referral_point",
            title="Tebrikler! Referans Bonusu Kazandınız!",
            message=f"Yönetici tarafından atanan referans bonusu: {bonus_points} puan"
        )
        
        # 변경사항 커밋
        db.commit()
        
        return {
            "message": "추천 관계가 성공적으로 생성되었습니다.",
            "referral": {
                "referrer": {
                    "id": referrer.id,
                    "email": referrer.email,
                    "name": f"{referrer.first_name} {referrer.last_name}",
                    "points_awarded": bonus_points,
                    "total_points": referrer_points.total_points
                },
                "referred": {
                    "id": referred.id,
                    "email": referred.email,
                    "name": f"{referred.first_name} {referred.last_name}",
                    "points_awarded": bonus_points,
                    "total_points": referred_points.total_points
                }
            }
        }
        
    except HTTPException:
        db.rollback()
        raise
    except Exception as e:
        db.rollback()
        logging.error(f"Error creating referral relationship: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"추천 관계 생성 중 오류가 발생했습니다: {str(e)}"
        )