"""New session modal for creating chat sessions.

Provides a modal screen that allows users to create a new chat session,
selecting either an agent or a direct model to use.
"""

from dataclasses import dataclass
from typing import Any
from uuid import UUID

from textual import on
from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical, VerticalScroll
from textual.screen import ModalScreen
from textual.widgets import (
    Button,
    Input,
    Label,
    Static,
    TabbedContent,
    TabPane,
    TextArea,
)

from alloy_runtime_sdk.api_client.client import ApiClient
from alloy_runtime_types.dtos.models import ModelListItemResponse

from cli.infrastructure.forms.agent_picker import AgentPicker
from cli.infrastructure.forms.base_picker import SingleSelectPicker


@dataclass
class NewSessionConfig:
    """Configuration for a new chat session.

    Supports two modes:
    - Agent mode: Use agent_id/agent_name (model comes from agent config)
    - Model mode: Use provider_key/provider_model_name directly
    """

    name: str | None
    # Agent mode fields
    agent_id: UUID | None = None
    agent_name: str | None = None
    # Model mode fields
    provider_key: str | None = None
    provider_model_name: str | None = None
    system_instruction: str | None = None

    @property
    def is_model_mode(self) -> bool:
        """Check if this config uses direct model mode."""
        return self.provider_key is not None and self.provider_model_name is not None

    @property
    def is_agent_mode(self) -> bool:
        """Check if this config uses agent mode."""
        return self.agent_id is not None


class SingleModelPicker(SingleSelectPicker[ModelListItemResponse]):
    """Single-select model picker for the new session modal.

    Unlike ModelPicker which allows multi-select for fallback models,
    this picker only allows selecting one model for direct model chat.
    """

    def __init__(
        self,
        client: ApiClient,
        placeholder: str = "Search models (e.g., gpt-4, claude, sonnet)...",
        **kwargs: Any,
    ) -> None:
        """Initialize the model picker.

        Args:
            client: ApiClient instance for API calls
            placeholder: Placeholder text for search input
        """
        super().__init__(
            client=client,
            placeholder=placeholder,
            empty_message="No model selected",
            **kwargs,
        )

    @property
    def selected_model(self) -> ModelListItemResponse | None:
        """Get the selected model."""
        return self._selected_item

    @property
    def selected_provider_key(self) -> str | None:
        """Get the provider key of the selected model."""
        if self._selected_item is None:
            return None
        return self._selected_item.provider_key

    @property
    def selected_model_name(self) -> str | None:
        """Get the model name of the selected model."""
        if self._selected_item is None:
            return None
        return self._selected_item.provider_model_name

    async def _fetch_items(self, query: str) -> list[ModelListItemResponse]:
        """Fetch models matching query from the API."""
        response = await self._client.list_models(
            search=query,
            configured_only=True,
            limit=50,
        )
        return list(response.models)

    def _format_item(self, item: ModelListItemResponse) -> str:
        """Format model for display in option list."""
        return f"{item.provider_key}:{item.provider_model_name}"

    def _get_item_id(self, item: ModelListItemResponse) -> str:
        """Get unique identifier for a model."""
        return f"{item.provider_key}:{item.provider_model_name}"


class NewSessionModal(ModalScreen[NewSessionConfig | None]):
    """Modal for creating a new chat session.

    Allows users to optionally name the session and select either:
    - An agent (uses agent's system instruction and models)
    - A model directly (optionally with a custom system instruction)

    Returns NewSessionConfig on create, or None if cancelled.

    Usage:
        def on_session_created(result: NewSessionConfig | None):
            if result is not None:
                # Create session with result
                pass

        self.app.push_screen(
            NewSessionModal(client=server_client),
            on_session_created
        )
    """

    BINDINGS = [
        Binding("escape", "cancel", "Cancel", show=True),
    ]

    DEFAULT_CSS = """
    NewSessionModal {
        align: center middle;
    }
    
    NewSessionModal > Vertical {
        width: 80;
        max-height: 40;
        background: $surface;
        border: thick $primary;
        padding: 1 2;
    }
    
    NewSessionModal .modal-title {
        text-align: center;
        text-style: bold;
        margin-bottom: 1;
    }
    
    NewSessionModal .section-label {
        margin-top: 1;
        text-style: bold;
    }
    
    NewSessionModal .help-text {
        color: $text-muted;
        margin-bottom: 1;
    }
    
    NewSessionModal .button-row {
        margin-top: 1;
        height: auto;
        align: center middle;
    }
    
    NewSessionModal .button-row Button {
        margin: 0 1;
    }
    
    NewSessionModal #session-name {
        margin-bottom: 1;
    }
    
    NewSessionModal TabbedContent {
        height: auto;
        max-height: 25;
    }
    
    NewSessionModal TabPane {
        height: auto;
        padding: 1;
    }
    
    NewSessionModal #system-instruction {
        height: 5;
        margin-top: 1;
    }
    
    NewSessionModal #model-tab-scroll {
        height: 100%;
        max-height: 20;
    }
    """

    def __init__(
        self,
        client: ApiClient,
        **kwargs: Any,
    ) -> None:
        """Initialize the new session modal.

        Args:
            client: ApiClient instance for API calls
        """
        super().__init__(**kwargs)
        self._client = client
        self._active_tab: str = "agent"

    def compose(self) -> ComposeResult:
        with Vertical():
            yield Label("New Chat Session", classes="modal-title")

            yield Static("Session Name (optional):", classes="section-label")
            yield Input(
                placeholder="Enter a name for this chat...",
                id="session-name",
            )

            with TabbedContent(id="mode-tabs"):
                with TabPane("Agent", id="agent-tab"):
                    yield Static(
                        "Choose an agent to chat with. The agent's system instruction "
                        "and configured models will be used.",
                        classes="help-text",
                    )
                    yield AgentPicker(
                        client=self._client,
                        placeholder="Search for an agent...",
                        id="agent-picker",
                    )

                with TabPane("Model", id="model-tab"):
                    with VerticalScroll(id="model-tab-scroll"):
                        yield Static(
                            "Chat directly with a model. Optionally provide a system instruction.",
                            classes="help-text",
                        )
                        yield SingleModelPicker(
                            client=self._client,
                            placeholder="Search for a model...",
                            id="model-picker",
                        )
                        yield Static(
                            "System Instruction (optional):", classes="section-label"
                        )
                        yield TextArea(
                            id="system-instruction",
                        )

            with Horizontal(classes="button-row"):
                yield Button("Create", id="create-btn", variant="success")
                yield Button("Cancel", id="cancel-btn", variant="default")

    def on_mount(self) -> None:
        """Focus the session name input on mount."""
        self.query_one("#session-name", Input).focus()

    @on(TabbedContent.TabActivated)
    def on_tab_activated(self, event: TabbedContent.TabActivated) -> None:
        """Track which tab is active."""
        if event.pane.id == "agent-tab":
            self._active_tab = "agent"
        elif event.pane.id == "model-tab":
            self._active_tab = "model"

    @on(Button.Pressed, "#create-btn")
    def on_create_pressed(self, event: Button.Pressed) -> None:
        """Create session and dismiss with config."""
        name_input = self.query_one("#session-name", Input)
        name = name_input.value.strip() or None

        if self._active_tab == "agent":
            # Agent mode
            agent_picker = self.query_one("#agent-picker", AgentPicker)
            agent_id_str = agent_picker.selected_agent_id
            agent_id = UUID(agent_id_str) if agent_id_str else None
            agent_name = agent_picker.selected_agent_name

            config = NewSessionConfig(
                name=name,
                agent_id=agent_id,
                agent_name=agent_name,
            )
        else:
            # Model mode
            model_picker = self.query_one("#model-picker", SingleModelPicker)
            system_input = self.query_one("#system-instruction", TextArea)

            provider_key = model_picker.selected_provider_key
            model_name = model_picker.selected_model_name
            system_instruction = system_input.text.strip() or None

            config = NewSessionConfig(
                name=name,
                provider_key=provider_key,
                provider_model_name=model_name,
                system_instruction=system_instruction,
            )

        self.dismiss(config)

    @on(Button.Pressed, "#cancel-btn")
    def on_cancel_pressed(self, event: Button.Pressed) -> None:
        """Cancel and dismiss with None."""
        self.dismiss(None)

    def action_cancel(self) -> None:
        """Cancel via escape key."""
        self.dismiss(None)
