import uuid
from pathlib import Path

from fastapi import APIRouter, Depends, HTTPException, UploadFile, status
from sqlalchemy.ext.asyncio import AsyncSession

from src.auth.dependencies import _get_user, get_current_user_id, get_db_session
from src.models.user import User
from src.schemas.user import UserProfileResponse, UserProfileUpdate

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

UPLOAD_DIR = Path("uploads/avatars")
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
ALLOWED_CONTENT_TYPES = {"image/png", "image/jpeg", "image/jpg"}
MAX_AVATAR_SIZE = 2 * 1024 * 1024  # 2MB


@router.get(
    "/me",
    response_model=UserProfileResponse,
    summary="Get current user profile",
    description="Retrieve the profile of the currently authenticated user.",
)
async def get_profile(
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> User:
    """Get the current user's profile.

    Args:
        user_id: ID of the authenticated user.
        session: Database session.

    Returns:
        The user's profile information.
    """
    return await _get_user(session, user_id)


@router.put(
    "/me",
    response_model=UserProfileResponse,
    summary="Update user profile",
    description="Update the current user's profile information.",
)
async def update_profile(
    data: UserProfileUpdate,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> User:
    """Update the current user's profile.

    Args:
        data: Profile update data with optional name and email.
        user_id: ID of the authenticated user.
        session: Database session.

    Returns:
        The updated user profile.
    """
    user = await _get_user(session, user_id)

    if data.name is not None:
        if len(data.name.strip()) == 0:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="name cannot be empty"
            )
        user.name = data.name.strip()

    if data.email is not None:
        if "@" not in data.email:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="invalid email"
            )
        user.email = data.email.strip()

    await session.commit()
    await session.refresh(user)
    return user


@router.post(
    "/me/avatar",
    response_model=UserProfileResponse,
    summary="Upload avatar",
    description="Upload a profile avatar image (PNG or JPG, max 2MB).",
)
async def upload_avatar(
    file: UploadFile,
    user_id: uuid.UUID = Depends(get_current_user_id),
    session: AsyncSession = Depends(get_db_session),
) -> User:
    """Upload a profile avatar image.

    Args:
        file: The image file to upload (PNG or JPG, max 2MB).
        user_id: ID of the authenticated user.
        session: Database session.

    Returns:
        The updated user profile with new avatar URL.
    """
    user = await _get_user(session, user_id)

    if file.content_type not in ALLOWED_CONTENT_TYPES:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"invalid file type: {file.content_type}. only png and jpg allowed",
        )

    content = await file.read()
    if len(content) > MAX_AVATAR_SIZE:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="file too large. max size is 2mb",
        )

    # Delete old avatar if exists
    if user.avatar_url:
        old_path = UPLOAD_DIR / Path(user.avatar_url).name
        if old_path.exists():
            old_path.unlink()

    # Save new avatar with UUID filename
    filename_part = file.filename or "avatar.png"
    ext = filename_part.split(".")[-1].lower() if "." in filename_part else "png"
    if ext not in {"png", "jpg", "jpeg"}:
        ext = "png"

    filename = f"{uuid.uuid4()}.{ext}"
    file_path = UPLOAD_DIR / filename
    file_path.write_bytes(content)

    user.avatar_url = f"/uploads/avatars/{filename}"
    await session.commit()
    await session.refresh(user)
    return user
