# app/api/v1/endpoints/users.py
from typing import List, Any, Dict, Optional
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form, BackgroundTasks
from sqlalchemy.orm import Session
from pydantic import BaseModel, Field
from app.api import deps
from app.schemas import user as user_schemas
from app.services.user_service import UserService
from app.services.media_service import MediaService
from app.core.config import settings
import logging
import os
import uuid
import json

logger = logging.getLogger('adimsayar')
router = APIRouter()

UPLOAD_DIR = "uploads/profile_images"
os.makedirs(UPLOAD_DIR, exist_ok=True)

# Create MediaService instance using local storage configuration
media_client = MediaService(
    storage_base_path=settings.STORAGE_BASE_PATH,
    base_url=settings.BASE_URL
)

# New Pydantic model for JSON login requests
class LoginRequest(BaseModel):
    username: str
    password: str

class StepNotificationSettingsUpdate(BaseModel):
    notification_frequency: int = Field(..., ge=0, le=10)  # 하루 0~10회 사이로 제한

@router.post("/register", response_model=user_schemas.User)
async def register_user(
    user_in: str = Form(...),
    profile_image: Optional[UploadFile] = File(None),
    db: Session = Depends(deps.get_db)
) -> Any:
    """
    Register a new user with an optional profile image.
    
    Expected form-data:
    - user_in: JSON string containing the registration data.
    - profile_image: (Optional) file upload for the profile image.
    """
    try:
        user_data = json.loads(user_in)
        user_payload = user_schemas.UserCreate(**user_data)

        # Check if email already exists
        if UserService.get_user_by_email(db, user_payload.email):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Email already registered"
            )

        # Process profile image if provided.
        if profile_image:
            # 업로드 시 "profile" 폴더 안으로 저장되고 고유한 UUID 파일명이 생성됩니다.
            file_url = media_client.upload_image(profile_image, "profile")
            user_payload.profile_image = file_url
        else:
            user_payload.profile_image = "profile/default_avatar.png"

        # Create the user using the service
        user = UserService.create_user(db, user_payload)
        logger.info(f"Successfully registered user: {user.email}")
        return user

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Registration failed: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Internal server error during registration"
        )

@router.get("/", response_model=List[user_schemas.User])
def get_users(
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(deps.get_db)
) -> Any:
    """Get list of users"""
    return UserService.get_users(db, skip=skip, limit=limit)

@router.get("/referral-codes", response_model=List[user_schemas.UserReferralCode])
def get_referral_codes(db: Session = Depends(deps.get_db)) -> Any:
    """Get list of referral codes for all active users"""
    try:
        referral_codes = UserService.get_all_referral_codes(db)
        return referral_codes
    except Exception as e:
        logger.error(f"Error fetching referral codes: {str(e)}", exc_info=True)
        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Error fetching referral codes")

@router.get("/{user_id}", response_model=user_schemas.User)
def get_user(user_id: int, db: Session = Depends(deps.get_db)) -> Any:
    """Get user by ID"""
    user = UserService.get_user(db, user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    return user

@router.put("/{user_id}", response_model=user_schemas.User)
async def update_user(
    user_id: int,
    user_in: str = Form(...),
    profile_image: Optional[UploadFile] = File(None),
    db: Session = Depends(deps.get_db)
) -> Any:
    """
    Update user information, including an optional profile image.
    """
    try:
        user_data = json.loads(user_in)
        update_payload = user_schemas.UserUpdate(**user_data)

        if profile_image:
            file_url = media_client.upload_image(profile_image, "profile")
            update_payload.profile_image = file_url

        user = UserService.update_user(db, user_id, update_payload)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="User not found"
            )
        return user

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Error updating user: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=str(e)
        )

@router.post("/login")
def login(
    login_data: LoginRequest,
    background_tasks: BackgroundTasks,
    db: Session = Depends(deps.get_db)
) -> Any:
    """
    Login endpoint accepting credentials via a JSON payload.
    
    Expected JSON body:
    {
        "username": "user@example.com",
        "password": "secret123"
    }
    """
    try:
        result = UserService.authenticate_user(
            db, 
            email=login_data.username, 
            password=login_data.password,
            background_tasks=background_tasks
        )
        
        if not result:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid credentials",
                headers={"WWW-Authenticate": "Bearer"},
            )
            
        logger.info(f"Successful login: {login_data.username}")
        return result
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Login failed: {str(e)}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Authentication process failed"
        )

@router.delete("/{user_id}", response_model=user_schemas.User)
def delete_user(user_id: int, db: Session = Depends(deps.get_db)) -> Any:
    """
    Delete a user by setting its status to 0.
    """
    user = UserService.delete_user(db, user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    return user

@router.put("/step-notification-settings", response_model=user_schemas.User)
def update_step_notification_settings(
    settings: StepNotificationSettingsUpdate,
    db: Session = Depends(deps.get_db),
    current_user = Depends(deps.get_current_user)
):
    """사용자의 걸음수 알림 빈도 설정을 업데이트합니다."""
    user = db.query(user_schemas.User).filter(user_schemas.User.id == current_user.id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    
    user.step_notification_frequency = settings.notification_frequency
    db.commit()
    db.refresh(user)
    return user

@router.post("/push-step-notification")
def push_step_notification(
    user_id: int,
    steps_count: int,
    db: Session = Depends(deps.get_db)
):
    """
    임시 테스트용 엔드포인트:
    주어진 user_id와 steps_count를 기반으로 오늘 날짜의 걸음 기록을 생성하거나 업데이트한 후,
    check_and_send_step_notification 함수를 호출하여 알림 전송 여부를 확인합니다.
    
    Request 파라미터:
    - user_id: 테스트할 유저의 ID
    - steps_count: 테스트할 걸음 수
    
    응답:
    - 알림 발송 로직이 실행되었음을 확인하는 메시지
    """
    from datetime import date
    from app.models.user import User
    from app.models.step_record import StepRecord
    from app.services.step_record_service import check_and_send_step_notification

    # 유저 조회
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    # 오늘 날짜의 StepRecord 조회 (없으면 새롭게 생성)
    today = date.today()
    step_record = db.query(StepRecord).filter(
        StepRecord.user_id == user_id,
        StepRecord.record_date == today
    ).first()

    if step_record is None:
        step_record = StepRecord(
            user_id=user_id,
            record_date=today,
            steps_count=steps_count,
            points_earned=0,
            calories_burned=0.0,
            distance_km=0.0,
            goal_achieved=False,
            sync_source="test"
        )
        db.add(step_record)
        db.commit()
        db.refresh(step_record)
    else:
        step_record.steps_count = steps_count
        db.commit()
        db.refresh(step_record)

    # 알림 로직 호출: 조건에 따라 ExpoPushNotificationService.send_push_to_user 함수 호출됨
    check_and_send_step_notification(db, user_id, step_record)

    return {"message": "Test notification triggered", "user_id": user_id, "steps_count": steps_count}

@router.get("/check-points/{user_id}", response_model=Dict[str, Any])
def check_user_points(
    user_id: int,
    db: Session = Depends(deps.get_db)
) -> Any:
    """
    사용자의 포인트 정보와 트랜잭션 내역을 조회합니다.
    
    Args:
        user_id: 조회할 사용자 ID
        
    Returns:
        Dict: 사용자의 포인트 정보와 트랜잭션 내역
    """
    # 사용자 조회
    from app.models.user import User
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail=f"User with ID {user_id} not found")
    
    # 포인트 정보 조회
    from app.models.user_points import UserPoints
    points = db.query(UserPoints).filter(UserPoints.user_id == user_id).first()
    
    # 트랜잭션 내역 조회
    from app.models.point_transaction import PointTransaction
    transactions = db.query(PointTransaction).filter(
        PointTransaction.user_id == user_id
    ).order_by(PointTransaction.created_at.desc()).all()
    
    # 응답 데이터 구성
    return {
        "user_id": user_id,
        "email": user.email,
        "first_name": user.first_name,
        "last_name": user.last_name,
        "total_points": points.total_points if points else 0,
        "transactions": [
            {
                "id": tx.id,
                "transaction_type": tx.transaction_type,
                "amount": tx.amount,
                "description": tx.description,
                "created_at": tx.created_at.isoformat()
            } for tx in transactions
        ]
    }