"""Tool config update modal for editing existing tool configurations.

Provides a modal screen that allows users to update an existing tool configuration
with all fields pre-populated from the current values.
"""

import json
from typing import Any

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

from cli.infrastructure.scope_utils import format_scope_label
from cli.tui.widgets.base_form_modal import BaseFormModal

from alloy_runtime_sdk.api_client.client import ApiClient
from alloy_runtime_types.dtos.tool_configs import (
    GetToolConfigResponse,
    UpdateToolConfigRequest,
)

from cli.tui.widgets.tool_config_create_modal import ToolConfigCreateResult


class ToolConfigUpdateModal(BaseFormModal[ToolConfigCreateResult]):
    """Modal for updating an existing tool configuration.

    Pre-populates all fields from the existing config.
    Scope and tool_id are read-only (cannot be changed after creation).

    Usage:
        def on_config_updated(result: ToolConfigCreateResult | None):
            if result is not None:
                self.notify(f"Updated config: {result.config_name}")
                self._do_search("")  # Refresh list

        client = await self.app.store.get_client()
        config = await client.get_tool_config(config_id)
        self.app.push_screen(
            ToolConfigUpdateModal(client=client, config=config),
            on_config_updated
        )
    """

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

        Args:
            client: ApiClient instance for API calls
            config: The existing tool config to update
        """
        super().__init__(**kwargs)
        self._client = client
        self._config = config

    def compose(self) -> ComposeResult:
        with VerticalScroll(id="tool-config-update-modal"):
            yield Label("Update Tool Config", classes="modal-title")

            # ===== READ-ONLY INFO =====
            yield Static("[bold]Info (read-only)[/]", classes="form-section")

            yield Static(f"[dim]ID:[/] {self._config.id}")
            yield Static(f"[dim]Slug:[/] {self._config.slug}")
            yield Static(f"[dim]Tool:[/] {self._config.tool_id}")
            yield Static(
                f"[dim]Scope:[/] {format_scope_label(str(self._config.organization_id) if self._config.organization_id else None, str(self._config.user_id) if self._config.user_id else None)}"
            )

            # ===== EDITABLE FIELDS =====
            yield Static("[bold]Editable Fields[/]", classes="form-section")

            yield Static("Name", classes="field-label")
            yield Input(
                value=self._config.name,
                id="name-input",
            )

            yield Static(
                "Configuration (JSON object with tool parameters)",
                classes="field-label",
            )
            yield TextArea(
                id="config-textarea",
                classes="definition-input",
            )

            yield Static("Description", classes="field-label")
            yield Input(
                value=self._config.description or "",
                placeholder="Brief description of this configuration",
                id="description-input",
            )

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

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

    def on_mount(self) -> None:
        """Pre-populate the config textarea and focus name input."""
        config_text = json.dumps(self._config.config, indent=2)
        self.query_one("#config-textarea", TextArea).text = config_text
        self.query_one("#name-input", Input).focus()

    @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 len(name) > 255:
            raise ValueError("Name must be 255 characters or less")

        config_text = self.query_one("#config-textarea", TextArea).text.strip()
        if not config_text:
            raise ValueError("Configuration is required")

        try:
            config = json.loads(config_text)
            if not isinstance(config, dict):
                raise ValueError(
                    "Configuration must be a JSON object (not array/primitive)"
                )
        except json.JSONDecodeError as e:
            raise ValueError(f"Invalid JSON in configuration: {e.msg}")

    def _build_request(self) -> UpdateToolConfigRequest:
        """Build the API request with only changed fields."""
        name = self.query_one("#name-input", Input).value.strip()
        config_text = self.query_one("#config-textarea", TextArea).text.strip()
        config = json.loads(config_text)
        description = self.query_one("#description-input", Input).value.strip()

        # Only include fields that have changed
        request_kwargs: dict[str, Any] = {}

        if name != self._config.name:
            request_kwargs["name"] = name

        if config != self._config.config:
            request_kwargs["config"] = config

        # Description: empty string clears it, None means no change
        if description != (self._config.description or ""):
            request_kwargs["description"] = description if description else ""

        return UpdateToolConfigRequest(**request_kwargs)

    @work(exclusive=True)
    async def _finalize_submission(self) -> None:
        """Submit to API."""
        try:
            request = self._build_request()
            response = await self._client.update_tool_config(
                str(self._config.id), request
            )

            result = ToolConfigCreateResult(
                config_id=str(response.id),
                config_name=response.name,
            )
            self.dismiss(result)

        except Exception as e:
            error_msg = str(e)
            # Provide user-friendly error messages
            if "409" in error_msg or "conflict" in error_msg.lower():
                self._show_error(
                    "A tool config with this name already exists in this scope"
                )
            elif "validation" in error_msg.lower():
                self._show_error(f"Invalid configuration: {error_msg}")
            else:
                self._show_error(f"Failed to update tool config: {error_msg}")
