"""Decks API router for Mantimon TCG.

This module provides REST endpoints for deck management including
creating, reading, updating, and deleting decks, as well as validation.

The backend is stateless - deck rules come from the request via DeckConfig.
Frontend provides the rules appropriate for the game mode (campaign, freeplay, custom).

Endpoints:
    GET /decks - List all user's decks
    POST /decks - Create a new deck
    GET /decks/{deck_id} - Get a specific deck
    PUT /decks/{deck_id} - Update a deck
    DELETE /decks/{deck_id} - Delete a deck
    POST /decks/validate - Validate a deck without saving
"""

from uuid import UUID

from fastapi import APIRouter, HTTPException, status

from app.api.deps import CardServiceDep, CollectionServiceDep, CurrentUser, DeckServiceDep
from app.repositories.protocols import UNSET
from app.schemas.deck import (
    DeckCreateRequest,
    DeckListResponse,
    DeckResponse,
    DeckUpdateRequest,
    DeckValidateRequest,
    DeckValidationResponse,
)
from app.services.deck_service import DeckLimitExceededError, DeckNotFoundError
from app.services.deck_validator import validate_deck

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


@router.get("", response_model=DeckListResponse)
async def list_decks(
    current_user: CurrentUser,
    deck_service: DeckServiceDep,
) -> DeckListResponse:
    """Get all decks for the authenticated user.

    Returns a list of all user's decks along with count and limit information.
    Premium users have unlimited decks (deck_limit=None).

    Returns:
        DeckListResponse with decks, count, and limit.
    """
    decks = await deck_service.get_user_decks(current_user.id)

    # Convert DeckEntry DTOs to DeckResponse
    deck_responses = [
        DeckResponse(
            id=d.id,
            name=d.name,
            description=d.description,
            cards=d.cards,
            energy_cards=d.energy_cards,
            is_valid=d.is_valid,
            validation_errors=d.validation_errors,
            is_starter=d.is_starter,
            starter_type=d.starter_type,
            created_at=d.created_at,
            updated_at=d.updated_at,
        )
        for d in decks
    ]

    # Premium users have unlimited decks
    deck_limit = None if current_user.has_active_premium else current_user.max_decks

    return DeckListResponse(
        decks=deck_responses,
        deck_count=len(decks),
        deck_limit=deck_limit,
    )


@router.post("", response_model=DeckResponse, status_code=status.HTTP_201_CREATED)
async def create_deck(
    deck_in: DeckCreateRequest,
    current_user: CurrentUser,
    deck_service: DeckServiceDep,
) -> DeckResponse:
    """Create a new deck.

    Validates the deck composition and stores it. Invalid decks CAN be saved
    (with validation errors) to support work-in-progress deck building.

    Args:
        deck_in: Deck creation request with name, cards, energy, and config.

    Returns:
        The created deck with validation state.

    Raises:
        400: If user has reached their deck limit.
    """
    try:
        deck = await deck_service.create_deck(
            user_id=current_user.id,
            name=deck_in.name,
            cards=deck_in.cards,
            energy_cards=deck_in.energy_cards,
            deck_config=deck_in.deck_config,
            max_decks=current_user.max_decks,
            validate_ownership=deck_in.validate_ownership,
            description=deck_in.description,
        )
    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,
    )


@router.get("/{deck_id}", response_model=DeckResponse)
async def get_deck(
    deck_id: UUID,
    current_user: CurrentUser,
    deck_service: DeckServiceDep,
) -> DeckResponse:
    """Get a specific deck by ID.

    Only returns decks owned by the authenticated user.

    Args:
        deck_id: The deck's UUID.

    Returns:
        The deck details.

    Raises:
        404: If deck not found or not owned by user.
    """
    try:
        deck = await deck_service.get_deck(current_user.id, deck_id)
    except DeckNotFoundError:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Deck not found",
        ) 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,
    )


@router.put("/{deck_id}", response_model=DeckResponse)
async def update_deck(
    deck_id: UUID,
    deck_in: DeckUpdateRequest,
    current_user: CurrentUser,
    deck_service: DeckServiceDep,
) -> DeckResponse:
    """Update an existing deck.

    Only provided fields are updated. If cards or energy_cards change,
    the deck is re-validated with the provided deck_config.

    To clear the description, explicitly send `"description": null` in the request.
    Omitting the field keeps the existing description.

    Args:
        deck_id: The deck's UUID.
        deck_in: Update request with optional fields.

    Returns:
        The updated deck.

    Raises:
        404: If deck not found or not owned by user.
    """
    # Check if description was explicitly provided (even if null)
    # UNSET means "keep existing", whereas None means "clear"
    description = deck_in.description if "description" in deck_in.model_fields_set else UNSET

    try:
        deck = await deck_service.update_deck(
            user_id=current_user.id,
            deck_id=deck_id,
            deck_config=deck_in.deck_config,
            name=deck_in.name,
            cards=deck_in.cards,
            energy_cards=deck_in.energy_cards,
            validate_ownership=deck_in.validate_ownership,
            description=description,
        )
    except DeckNotFoundError:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Deck not found",
        ) 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,
    )


@router.delete("/{deck_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_deck(
    deck_id: UUID,
    current_user: CurrentUser,
    deck_service: DeckServiceDep,
) -> None:
    """Delete a deck.

    Only deletes decks owned by the authenticated user.

    Args:
        deck_id: The deck's UUID.

    Raises:
        404: If deck not found or not owned by user.
    """
    try:
        await deck_service.delete_deck(current_user.id, deck_id)
    except DeckNotFoundError:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Deck not found",
        ) from None


@router.post("/validate", response_model=DeckValidationResponse)
async def validate_deck_endpoint(
    request: DeckValidateRequest,
    current_user: CurrentUser,
    card_service: CardServiceDep,
    collection_service: CollectionServiceDep,
) -> DeckValidationResponse:
    """Validate a deck composition without saving.

    Useful for checking if a deck is valid before creating it.
    Uses the provided deck_config rules from the frontend.

    Args:
        request: Validation request with cards, energy, and config.

    Returns:
        Validation result with is_valid and any errors.
    """
    # Get owned cards if validating ownership (campaign mode)
    owned_cards: dict[str, int] | None = None
    if request.validate_ownership:
        owned_cards = await collection_service.get_owned_cards_dict(current_user.id)

    # Use the pure validation function with config from request
    result = validate_deck(
        cards=request.cards,
        energy_cards=request.energy_cards,
        deck_config=request.deck_config,
        card_lookup=card_service.get_card,
        owned_cards=owned_cards,
    )

    return DeckValidationResponse(
        is_valid=result.is_valid,
        errors=result.errors,
    )
