"""User API router for Mantimon TCG.

This module provides endpoints for user profile management:
- Get current user profile
- Update profile (display name, avatar)
- List linked OAuth accounts
- Session management
- Starter deck selection (one-time for new players)

All endpoints require authentication.

Example:
    # Get current user
    GET /api/users/me
    Authorization: Bearer <access_token>

    # Update profile
    PATCH /api/users/me
    {"display_name": "NewName"}

    # Select starter deck
    POST /api/users/me/starter-deck
    {"starter_type": "grass"}
"""

from fastapi import APIRouter, HTTPException, status
from pydantic import BaseModel, Field

from app.api.deps import CurrentUser, DeckServiceDep, UserServiceDep
from app.schemas.deck import DeckResponse, StarterDeckSelectRequest, StarterStatusResponse
from app.schemas.user import UserResponse, UserUpdate
from app.services.deck_service import DeckLimitExceededError, StarterAlreadySelectedError
from app.services.token_store import token_store
from app.services.user_service import AccountLinkingError

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


class LinkedAccountResponse(BaseModel):
    """Response for a linked OAuth account."""

    provider: str = Field(..., description="OAuth provider name")
    email: str | None = Field(None, description="Email from this provider")
    linked_at: str = Field(..., description="When account was linked (ISO format)")


class SessionsResponse(BaseModel):
    """Response for active sessions count."""

    active_sessions: int = Field(..., description="Number of active sessions")


@router.get("/me", response_model=UserResponse)
async def get_current_user_profile(
    user: CurrentUser,
) -> UserResponse:
    """Get the current user's profile.

    Returns:
        User profile information.
    """
    return UserResponse.model_validate(user)


@router.patch("/me", response_model=UserResponse)
async def update_current_user_profile(
    user: CurrentUser,
    user_service: UserServiceDep,
    update_data: UserUpdate,
) -> UserResponse:
    """Update the current user's profile.

    Only provided fields are updated.

    Args:
        update_data: Fields to update (display_name, avatar_url).

    Returns:
        Updated user profile.
    """
    updated_user = await user_service.update(user.id, update_data)
    return UserResponse.model_validate(updated_user)


@router.get("/me/linked-accounts", response_model=list[LinkedAccountResponse])
async def get_linked_accounts(
    user: CurrentUser,
) -> list[LinkedAccountResponse]:
    """Get all OAuth accounts linked to the current user.

    Returns the primary OAuth provider plus any additional linked accounts.

    Returns:
        List of linked OAuth accounts.
    """
    accounts = []

    # Add primary OAuth account
    accounts.append(
        LinkedAccountResponse(
            provider=user.oauth_provider,
            email=user.email,
            linked_at=user.created_at.isoformat(),
        )
    )

    # Add additional linked accounts
    for linked in user.linked_accounts:
        accounts.append(
            LinkedAccountResponse(
                provider=linked.provider,
                email=linked.email,
                linked_at=linked.linked_at.isoformat(),
            )
        )

    return accounts


@router.get("/me/sessions", response_model=SessionsResponse)
async def get_active_sessions(
    user: CurrentUser,
) -> SessionsResponse:
    """Get the number of active sessions for the current user.

    Each session corresponds to a valid refresh token.

    Returns:
        Number of active sessions.
    """
    from uuid import UUID

    user_id = UUID(user.id) if isinstance(user.id, str) else user.id
    count = await token_store.get_active_session_count(user_id)

    return SessionsResponse(active_sessions=count)


@router.delete("/me/link/{provider}", status_code=status.HTTP_204_NO_CONTENT)
async def unlink_oauth_account(
    user: CurrentUser,
    user_service: UserServiceDep,
    provider: str,
) -> None:
    """Unlink an OAuth provider from the current user's account.

    Cannot unlink the primary OAuth provider (the one used to create the account).

    Args:
        provider: OAuth provider name to unlink ('google' or 'discord').

    Raises:
        HTTPException: 400 if trying to unlink primary provider.
        HTTPException: 404 if provider is not linked.
    """
    provider = provider.lower()

    if provider not in ("google", "discord"):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Unknown provider: {provider}",
        )

    try:
        unlinked = await user_service.unlink_oauth_account(user.id, user.oauth_provider, provider)
        if not unlinked:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail=f"{provider.title()} is not linked to your account",
            )
    except AccountLinkingError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e),
        ) from None


# =============================================================================
# Starter Deck Endpoints
# =============================================================================


@router.get("/me/starter-status", response_model=StarterStatusResponse)
async def get_starter_status(
    user: CurrentUser,
    deck_service: DeckServiceDep,
) -> StarterStatusResponse:
    """Check if user has already selected a starter deck.

    New users need to select a starter deck before playing.
    This endpoint checks if they've already made that selection.

    Returns:
        StarterStatusResponse with has_starter flag and starter_type.
    """
    has_starter, starter_type = await deck_service.has_starter_deck(user.id)

    return StarterStatusResponse(
        has_starter=has_starter,
        starter_type=starter_type,
    )


@router.post("/me/starter-deck", response_model=DeckResponse, status_code=status.HTTP_201_CREATED)
async def select_starter_deck(
    request: StarterDeckSelectRequest,
    user: CurrentUser,
    deck_service: DeckServiceDep,
) -> DeckResponse:
    """Select and create a starter deck for a new user.

    This is a one-time operation that atomically:
    1. Validates the starter type
    2. Creates the starter deck (protected by unique constraint)
    3. Grants all starter deck cards to the user's collection

    Race conditions are handled by a database unique constraint that prevents
    multiple starter decks per user.

    Available starter types: grass, fire, water, psychic, lightning

    Args:
        request: Starter deck selection with type and optional config.

    Returns:
        The created starter deck.

    Raises:
        400: If starter already selected or invalid starter_type.
    """
    try:
        deck = await deck_service.select_and_grant_starter_deck(
            user_id=user.id,
            starter_type=request.starter_type,
            deck_config=request.deck_config,
            max_decks=user.max_decks,
        )
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e),
        ) from None
    except StarterAlreadySelectedError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e),
        ) from None
    except DeckLimitExceededError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e),
        ) from None

    return DeckResponse(
        id=deck.id,
        name=deck.name,
        description=deck.description,
        cards=deck.cards,
        energy_cards=deck.energy_cards,
        is_valid=deck.is_valid,
        validation_errors=deck.validation_errors,
        is_starter=deck.is_starter,
        starter_type=deck.starter_type,
        created_at=deck.created_at,
        updated_at=deck.updated_at,
    )
