"""Роутер профиля текущего пользователя, аватара, картинок фона и списка пользователей."""

import uuid
from pathlib import Path
from typing import Annotated

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

from api.deps import get_current_user
from core.config import get_settings
from core.db import get_session
from core.security import hash_password, verify_password
from models.user import User
from models.user_background import UserBackground
from repositories.users import UserRepository
from schemas.auth import (
    PasswordChangeIn,
    ProfileUpdateIn,
    UserBackgroundOut,
    UserBackgroundsOut,
    UserListItemOut,
    UserProfileOut,
)
from services.avatars import AvatarInvalidTypeError, AvatarTooLargeError, avatar_url
from services.backgrounds import (
    MAX_BACKGROUNDS_PER_USER,
    BackgroundInvalidTypeError,
    BackgroundLimitReachedError,
    BackgroundTooLargeError,
    add_background,
    background_url,
    delete_background,
    list_backgrounds,
)
from services.profile import (
    TeamNotFoundError,
    clear_avatar,
    resolve_team_name,
    update_profile_fields,
)
from services.profile import set_avatar as _set_avatar

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

# Число совпадений, возвращаемых поиском по `q` (пикер участников).
SEARCH_LIMIT = 20


@router.get("/me", response_model=UserProfileOut)
async def read_current_user(
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
) -> UserProfileOut:
    """Вернуть профиль текущего аутентифицированного пользователя."""
    return await _to_profile_out(session, user)


@router.patch("/me", response_model=UserProfileOut)
async def update_current_user(
    data: ProfileUpdateIn,
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
) -> UserProfileOut:
    """Изменить ФИО и/или команду текущего пользователя; email — read-only."""
    try:
        await update_profile_fields(
            session,
            user,
            name_user=data.name_user,
            team_id=data.team_id,
            team_id_is_set="team_id" in data.model_fields_set,
        )
    except TeamNotFoundError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="team_not_found") from exc
    await session.commit()
    return await _to_profile_out(session, user)


@router.post("/me/avatar", response_model=UserProfileOut)
async def upload_current_user_avatar(
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
    file: Annotated[UploadFile, File()],
) -> UserProfileOut:
    """Загрузить аватар текущего пользователя (jpeg/png/webp, до 2 МБ)."""
    try:
        await _set_avatar(_media_root(), user, file)
    except AvatarTooLargeError as exc:
        raise HTTPException(
            status_code=status.HTTP_413_CONTENT_TOO_LARGE, detail="avatar_too_large"
        ) from exc
    except AvatarInvalidTypeError as exc:
        raise HTTPException(
            status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, detail="avatar_invalid_type"
        ) from exc
    await session.commit()
    return await _to_profile_out(session, user)


@router.delete("/me/avatar", status_code=status.HTTP_204_NO_CONTENT)
async def delete_current_user_avatar(
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
) -> None:
    """Удалить аватар текущего пользователя."""
    clear_avatar(_media_root(), user)
    await session.commit()


@router.get("/me/backgrounds", response_model=UserBackgroundsOut)
async def list_current_user_backgrounds(
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
) -> UserBackgroundsOut:
    """Свои картинки для замены фона видео + лимит на их число."""
    items = await list_backgrounds(session, user.id)
    return _to_backgrounds_out(items)


@router.post(
    "/me/backgrounds", response_model=UserBackgroundsOut, status_code=status.HTTP_201_CREATED
)
async def upload_current_user_background(
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
    file: Annotated[UploadFile, File()],
) -> UserBackgroundsOut:
    """Загрузить свою картинку фона (jpeg/png/webp, до 2 МБ, не более 10 штук).

    Возвращает весь список заново, а не одну добавленную запись: интерфейсу всё
    равно нужен свежий список с актуальным остатком лимита, и лишний GET следом
    за POST не нужен.
    """
    try:
        await add_background(session, _media_root(), user.id, file)
    except BackgroundLimitReachedError as exc:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT, detail="background_limit_reached"
        ) from exc
    except BackgroundTooLargeError as exc:
        raise HTTPException(
            status_code=status.HTTP_413_CONTENT_TOO_LARGE, detail="background_too_large"
        ) from exc
    except BackgroundInvalidTypeError as exc:
        raise HTTPException(
            status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, detail="background_invalid_type"
        ) from exc
    await session.commit()
    return _to_backgrounds_out(await list_backgrounds(session, user.id))


@router.delete("/me/backgrounds/{background_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_current_user_background(
    background_id: uuid.UUID,
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
) -> None:
    """Удалить свою картинку фона вместе с файлом на диске; чужую — 404."""
    if not await delete_background(session, _media_root(), user.id, background_id):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="background_not_found")
    await session.commit()


@router.post("/me/password", status_code=status.HTTP_204_NO_CONTENT)
async def change_current_user_password(
    data: PasswordChangeIn,
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
) -> None:
    """Сменить пароль текущего пользователя.

    Refresh-сессии сознательно НЕ отзываются — отзыв всех сессий появится
    вместе со сбросом пароля по email (v0.1.0, см. ADR-005
    `docs/architecture/adr/005-password-reset-deferred.md`).
    """
    if not await verify_password(data.current_password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="invalid_current_password"
        )
    user.password_hash = await hash_password(data.new_password)
    await session.commit()


@router.get("", response_model=list[UserListItemOut])
async def list_users(
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
    q: Annotated[str | None, Query()] = None,
) -> list[UserListItemOut]:
    """Пикер участников конференции: без `q` — полный список; с `q` — поиск имя/email."""
    media_root = _media_root()
    users = await UserRepository(session).search(q=q, limit=SEARCH_LIMIT)
    return [
        UserListItemOut(
            id=u.id, display_name=u.name_user, avatar_url=avatar_url(media_root, u.avatar_path)
        )
        for u in users
    ]


def _to_backgrounds_out(items: list[UserBackground]) -> UserBackgroundsOut:
    """Собрать ответ списка картинок фона: id + публичный URL, плюс лимит с сервера."""
    return UserBackgroundsOut(
        items=[UserBackgroundOut(id=item.id, url=background_url(item.path)) for item in items],
        limit=MAX_BACKGROUNDS_PER_USER,
    )


def _media_root() -> Path:
    """Каталог загруженных медиа-файлов (см. `core/config.py::Settings.media_root`)."""
    return Path(get_settings().media_root)


async def _to_profile_out(session: AsyncSession, user: User) -> UserProfileOut:
    """Собрать `UserProfileOut` — общая сборка для своего профиля и карточки в админке."""
    team_name = await resolve_team_name(session, user.team_id)
    return UserProfileOut(
        id=user.id,
        email=user.email,
        name_user=user.name_user,
        role=user.role,
        avatar_url=avatar_url(_media_root(), user.avatar_path),
        team_id=user.team_id,
        team_name=team_name,
    )
