"""Models list command implementation."""

from enum import Enum
from typing import Annotated, Optional

import typer

from alloy_runtime_types.enums.content_enums import SortOrder
from alloy_runtime_types.enums.model_enums import ModelSortField

from cli.commands.models.list.presenter import present_models_list
from cli.infrastructure.command import async_command, authenticated_client


class DisplayColumn(str, Enum):
    """Column display options."""

    MODEL = "model"
    PROVIDER = "provider"


def models_list_command(
    search: Optional[str] = typer.Option(
        None,
        "-s",
        "--search",
        help="Fuzzy search terms",
    ),
    provider_filter: Optional[str] = typer.Option(
        None,
        "-p",
        "--provider",
        help="Filter by provider",
    ),
    configured_only: bool = typer.Option(
        False,
        "--configured",
        help="Only show models with credentials",
    ),
    context_window_min: Optional[int] = typer.Option(
        None,
        "--context-window-min",
        min=1,
        help="Minimum context window size",
    ),
    context_window_max: Optional[int] = typer.Option(
        None,
        "--context-window-max",
        min=1,
        help="Maximum context window size",
    ),
    max_output_tokens_min: Optional[int] = typer.Option(
        None,
        "--max-output-min",
        min=1,
        help="Minimum max output tokens",
    ),
    max_output_tokens_max: Optional[int] = typer.Option(
        None,
        "--max-output-max",
        min=1,
        help="Maximum max output tokens",
    ),
    input_modalities: Annotated[
        Optional[list[str]],
        typer.Option(
            "--input-modality",
            help="Filter by input modality (repeatable)",
        ),
    ] = None,
    output_modalities: Annotated[
        Optional[list[str]],
        typer.Option(
            "--output-modality",
            help="Filter by output modality (repeatable)",
        ),
    ] = None,
    sort_by: Optional[str] = typer.Option(
        None,
        "--sort-by",
        help="Sort field: provider_key, provider_model_name, context_window, max_output_tokens",
    ),
    sort_order: Optional[str] = typer.Option(
        None,
        "--sort-order",
        help="Sort direction: asc or desc",
    ),
    limit: int = typer.Option(
        100,
        "--limit",
        min=1,
        max=10000,
        help="Maximum number of models to return",
    ),
    offset: int = typer.Option(
        0,
        "--offset",
        min=0,
        help="Number of matching models to skip before returning results",
    ),
    display: DisplayColumn | None = typer.Option(
        None,
        "--display",
        help="Show only: model or provider",
    ),
    extra_fields: bool = typer.Option(
        False,
        "--extra",
        help="Show detailed table",
    ),
) -> None:
    """List available AI models.

    Examples:
        alloy models list
        alloy models list -s "claude sonnet"
        alloy models list -p anthropic
        alloy models list --configured
        alloy models list --display model
        alloy models list --extra
        alloy models list --context-window-min 100000
        alloy models list --input-modality text --input-modality image
        alloy models list --sort-by context_window --sort-order desc
    """
    sort_by_enum: Optional[ModelSortField] = None
    if sort_by:
        try:
            sort_by_enum = ModelSortField(sort_by)
        except ValueError:
            valid = ", ".join(sf.value for sf in ModelSortField)
            raise typer.BadParameter(f"Invalid sort field '{sort_by}'. Valid: {valid}")

    sort_order_enum: Optional[SortOrder] = None
    if sort_order:
        try:
            sort_order_enum = SortOrder(sort_order)
        except ValueError:
            valid = ", ".join(so.value for so in SortOrder)
            raise typer.BadParameter(
                f"Invalid sort order '{sort_order}'. Valid: {valid}"
            )

    _execute_list(
        search=search,
        provider_filter=provider_filter,
        configured_only=configured_only,
        context_window_min=context_window_min,
        context_window_max=context_window_max,
        max_output_tokens_min=max_output_tokens_min,
        max_output_tokens_max=max_output_tokens_max,
        input_modalities=input_modalities,
        output_modalities=output_modalities,
        sort_by=sort_by_enum,
        sort_order=sort_order_enum,
        limit=limit,
        offset=offset,
        display=display,
        extra_fields=extra_fields,
    )


@async_command
async def _execute_list(
    search: Optional[str],
    provider_filter: Optional[str],
    configured_only: bool,
    context_window_min: Optional[int],
    context_window_max: Optional[int],
    max_output_tokens_min: Optional[int],
    max_output_tokens_max: Optional[int],
    input_modalities: Optional[list[str]],
    output_modalities: Optional[list[str]],
    sort_by: Optional[ModelSortField],
    sort_order: Optional[SortOrder],
    limit: int,
    offset: int,
    display: DisplayColumn | None,
    extra_fields: bool,
) -> None:
    """Execute list models operation."""
    async with authenticated_client() as (_config, client):
        response = await client.list_models(
            search=search,
            provider_filter=provider_filter,
            configured_only=configured_only,
            context_window_min=context_window_min,
            context_window_max=context_window_max,
            max_output_tokens_min=max_output_tokens_min,
            max_output_tokens_max=max_output_tokens_max,
            input_modalities=input_modalities,
            output_modalities=output_modalities,
            sort_by=sort_by,
            sort_order=sort_order,
            limit=limit,
            offset=offset,
        )

    present_models_list(response, display_column=display, extra_fields=extra_fields)
