"""Template update modal for editing existing template metadata.

Provides a modal screen that allows users to edit template name, description,
content type, visibility, and tags.
"""

import re
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any

from textual import on, work
from textual.app import ComposeResult
from textual.containers import Horizontal, VerticalScroll
from textual.widgets import (
    Button,
    Input,
    Label,
    RadioButton,
    RadioSet,
    Static,
)

from cli.tui.widgets.base_form_modal import BaseFormModal

from alloy_runtime_sdk.api_client.client import ApiClient
from alloy_runtime_types.dtos.templates import (
    TemplateListItemResponse,
    UpdateTemplateRequest,
)
from alloy_runtime_types.enums.template_enums import (
    TemplateContentType,
    TemplateVisibility,
)

from cli.infrastructure.forms.tag_picker import TagPicker

if TYPE_CHECKING:
    from cli.tui.app import AlloyRuntimeApp


@dataclass
class TemplateUpdateResult:
    """Result of successful template update."""

    template_id: str
    template_name: str


class TemplateUpdateModal(BaseFormModal[TemplateUpdateResult]):
    """Modal for updating template metadata.

    Provides a form with:
    - Editable fields: name, content type, visibility, description, tags
    - Read-only info: ID, version count

    Usage:
        def on_template_updated(result: TemplateUpdateResult | None):
            if result is not None:
                self.notify(f"Updated template: {result.template_name}")
                self._do_search("")  # Refresh list

        client = await self.app.store.get_client()
        self.app.push_screen(
            TemplateUpdateModal(client=client, template=template),
            on_template_updated
        )
    """

    app: "AlloyRuntimeApp"

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

        Args:
            client: ApiClient instance for API calls
            template: The template to edit
        """
        super().__init__(**kwargs)
        self._client = client
        self._template = template

    def compose(self) -> ComposeResult:
        with VerticalScroll(id="template-update-modal"):
            yield Label(f"Edit Template: {self._template.name}", classes="modal-title")

            # Template info (read-only)
            yield Static("[bold]Template Info[/]", classes="form-section")

            yield Static(
                f"[dim]ID:[/] {self._template.id}  "
                f"[dim]Versions:[/] {self._template.latest_version_number}",
                id="template-info",
                classes="info-display",
            )

            # Editable fields
            yield Static("[bold]Edit Properties[/]", classes="form-section")

            yield Static(
                "Name (lowercase, dots/dashes/underscores)", classes="field-label"
            )
            yield Input(
                value=self._template.name,
                placeholder="e.g., email.welcome-header, system.default_prompt",
                id="name-input",
            )

            yield Static("Content Type", classes="field-label")
            with RadioSet(id="content-type-radios"):
                yield RadioButton(
                    "System Instruction",
                    id="type-system",
                    value=self._template.content_type_id == "system_instruction",
                )
                yield RadioButton(
                    "User Message",
                    id="type-user",
                    value=self._template.content_type_id == "user_message",
                )
                yield RadioButton(
                    "Fragment",
                    id="type-fragment",
                    value=self._template.content_type_id == "fragment",
                )

            yield Static("Visibility", classes="field-label")
            with RadioSet(id="visibility-radios"):
                yield RadioButton(
                    "Private",
                    id="vis-private",
                    value=self._template.visibility_id == "private",
                )
                yield RadioButton(
                    "Organization",
                    id="vis-org",
                    value=self._template.visibility_id == "organization",
                )
                yield RadioButton(
                    "Public",
                    id="vis-public",
                    value=self._template.visibility_id == "public",
                )

            yield Static("Description", classes="field-label")
            yield Input(
                value=self._template.description or "",
                placeholder="Brief description of this template's purpose",
                id="description-input",
            )

            yield Static("Tags", classes="field-label")
            yield TagPicker(
                client=self._client,
                placeholder="Search tags...",
                empty_message="No tags selected",
                id="tag-picker",
            )

            # Error display
            yield Static("", id="error-display", classes="error-display")

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

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

    def _populate_tags(self) -> None:
        """Populate the tag picker with existing tags."""
        tag_picker = self.query_one("#tag-picker", TagPicker)
        existing_tags = [
            {"tag_path": t.tag_path, "display_name": t.display_name}
            for t in self._template.tags
        ]
        if existing_tags:
            tag_picker.set_initial_selection(existing_tags)

    @on(Button.Pressed, "#update-btn")
    def on_update_pressed(self, event: Button.Pressed) -> None:
        """Handle update button press."""
        self.action_submit()

    @on(Button.Pressed, "#cancel-btn")
    def on_cancel_pressed(self, event: Button.Pressed) -> None:
        """Handle cancel button press."""
        self.dismiss(None)

    def action_submit(self) -> None:
        """Handle form submission."""
        try:
            self._validate_fields()
            self._hide_error()
            self._finalize_submission()
        except ValueError as e:
            self._show_error(str(e))

    def _validate_fields(self) -> None:
        """Validate all required fields."""
        name = self.query_one("#name-input", Input).value.strip()
        if not name:
            raise ValueError("Name is required")

        if not re.match(r"^[a-z0-9._-]+$", name):
            raise ValueError(
                "Name must be lowercase alphanumeric with dots, dashes, or underscores only"
            )

    def _get_content_type(self) -> TemplateContentType:
        """Get content type from RadioSet."""
        radios = self.query_one("#content-type-radios", RadioSet)
        pressed = radios.pressed_button
        if pressed is None or pressed.id == "type-system":
            return TemplateContentType.SYSTEM_INSTRUCTION
        elif pressed.id == "type-user":
            return TemplateContentType.USER_MESSAGE
        else:
            return TemplateContentType.FRAGMENT

    def _get_visibility(self) -> TemplateVisibility:
        """Get visibility from RadioSet."""
        radios = self.query_one("#visibility-radios", RadioSet)
        pressed = radios.pressed_button
        if pressed is None or pressed.id == "vis-private":
            return TemplateVisibility.PRIVATE
        elif pressed.id == "vis-org":
            return TemplateVisibility.ORGANIZATION
        else:
            return TemplateVisibility.PUBLIC

    def _build_request(self) -> UpdateTemplateRequest:
        """Build the API request with only changed fields."""
        name = self.query_one("#name-input", Input).value.strip()
        description = self.query_one("#description-input", Input).value.strip()
        content_type = self._get_content_type()
        visibility = self._get_visibility()

        tag_picker = self.query_one("#tag-picker", TagPicker)
        new_tag_paths = tag_picker.selected_tags
        old_tag_paths = [t.tag_path for t in self._template.tags]

        # Only include fields that have changed
        request_name = name if name != self._template.name else None

        request_description: str | None = None
        old_description = self._template.description or ""
        if description != old_description:
            request_description = description  # Empty string clears description

        request_content_type = (
            content_type
            if content_type.value != self._template.content_type_id
            else None
        )
        request_visibility = (
            visibility if visibility.value != self._template.visibility_id else None
        )

        # Compare tag lists (order-insensitive)
        request_tag_paths = (
            new_tag_paths if sorted(new_tag_paths) != sorted(old_tag_paths) else None
        )

        return UpdateTemplateRequest(
            name=request_name,
            content_type=request_content_type,
            visibility=request_visibility,
            description=request_description,
            tag_paths=request_tag_paths,
        )

    @work(exclusive=True)
    async def _finalize_submission(self) -> None:
        """Submit to API."""
        try:
            request = self._build_request()

            # Check if anything actually changed
            if (
                request.name is None
                and request.content_type is None
                and request.visibility is None
                and request.description is None
                and request.tag_paths is None
            ):
                self.app.notify("No changes made", severity="information")
                self.dismiss(None)
                return

            response = await self._client.update_template(
                str(self._template.id), request
            )

            result = TemplateUpdateResult(
                template_id=str(response.template.id),
                template_name=response.template.name,
            )
            self.dismiss(result)

        except Exception as e:
            self._show_error(f"Failed to update template: {e}")
