"""
TUI Tab for managing docker-compose stacks from the composable registry
"""

from textual.widgets import Static, DataTable, Label, Button, Input
from textual.containers import Horizontal, Vertical, ScrollableContainer
from textual.screen import ModalScreen
from textual.app import ComposeResult
from textual import work


class EnvVarsDialog(ModalScreen):
    """Dialog for entering environment variables for a stack"""

    def __init__(self, app_instance, stack_name: str, env_vars_data: dict):
        """
        Args:
            app_instance: The app
            stack_name: Name of the stack being installed
            env_vars_data: Dict of {VAR_NAME: {"value": "default", "comment": "description"}}
        """
        super().__init__()
        self.app_instance = app_instance
        self.stack_name = stack_name
        self.env_vars_data = env_vars_data  # {name: {value, comment}}
        self.env_var_names = list(env_vars_data.keys())

    def compose(self) -> ComposeResult:
        yield Vertical(
            Label(f"Configure {self.stack_name}", id="env-dialog-title"),
            Label("Enter values for environment variables:", id="env-dialog-subtitle"),
            ScrollableContainer(
                Vertical(id="env-inputs-container"),
                id="env-scroll"
            ),
            Horizontal(
                Button("Install", id="env-install-btn", variant="primary"),
                Button("Cancel", id="env-cancel-btn", variant="default"),
                id="env-dialog-buttons"
            ),
            id="env-dialog"
        )

    def on_mount(self) -> None:
        container = self.query_one("#env-inputs-container", Vertical)

        for var_name, var_info in self.env_vars_data.items():
            default_value = var_info.get("value", "")
            comment = var_info.get("comment", "")

            # Create label with description
            if comment:
                label_text = f"[bold]{var_name}[/] [dim]({comment})[/]"
            else:
                label_text = f"[bold]{var_name}[/]"

            label = Label(label_text, classes="env-var-label")
            input_widget = Input(
                value=default_value,
                placeholder=f"Enter {var_name}",
                id=f"env-{var_name}",
                classes="env-var-input"
            )

            container.mount(label)
            container.mount(input_widget)

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "env-cancel-btn":
            self.dismiss(None)
            return

        if event.button.id == "env-install-btn":
            # Collect all env var values
            env_values = {}
            for var_name in self.env_var_names:
                try:
                    input_widget = self.query_one(f"#env-{var_name}", Input)
                    value = input_widget.value.strip()
                    if value:
                        env_values[var_name] = value
                except Exception:
                    pass

            self.dismiss(env_values)

    CSS = """
    #env-dialog {
        align: center middle;
        padding: 2;
        border: thick cyan;
        background: $surface;
        width: 80;
        height: 80%;
    }

    #env-dialog-title {
        text-align: center;
        text-style: bold;
        margin-bottom: 1;
    }

    #env-dialog-subtitle {
        color: $text-muted;
        margin-bottom: 1;
    }

    #env-scroll {
        height: 1fr;
        border: solid $primary;
        padding: 1;
    }

    #env-inputs-container {
        height: auto;
    }

    .env-var-label {
        margin-top: 1;
    }

    .env-var-input {
        margin-bottom: 1;
    }

    #env-dialog-buttons {
        align: center middle;
        margin-top: 1;
    }

    Button {
        min-width: 12;
        margin: 0 1;
    }
    """


class RegistryTab(Static):
    """Tab for managing docker-compose stacks from the composable registry"""

    # State
    selected_stack: str | None = None
    stacks_data: dict = {}  # {name: StackInfo}
    current_category: str = "infrastructure"

    def compose(self) -> ComposeResult:
        yield Label("Docker Compose Registry", id="registry-title")
        yield Label("Press [bold]R[/] to refresh | Stacks from [cyan]composable[/] registry", id="registry-help")

        # Category selector
        yield Horizontal(
            Button("Infrastructure", id="registry-cat-infrastructure", variant="primary"),
            Button("Services", id="registry-cat-services", variant="default"),
            id="registry-category-buttons"
        )

        yield Label("", id="registry-spacer1")

        # Stack list
        yield DataTable(id="registry-table", cursor_type="row")
        yield Label("Selected: [dim]None[/]", id="registry-selected-label")

        # Action buttons
        yield Horizontal(
            Button("Install", id="registry-install", variant="success", disabled=True),
            Button("Start", id="registry-start", variant="primary", disabled=True),
            Button("Stop", id="registry-stop", variant="warning", disabled=True),
            Button("Disable", id="registry-disable", variant="error", disabled=True),
            Button("Uninstall", id="registry-uninstall", variant="error", disabled=True),
            id="registry-action-buttons"
        )

    def on_mount(self) -> None:
        """Initialize the registry table"""
        self.refresh_registry()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        """Handle button presses"""
        button_id = event.button.id

        if button_id == "registry-cat-infrastructure":
            self.switch_category("infrastructure")
        elif button_id == "registry-cat-services":
            self.switch_category("services")
        elif button_id == "registry-install":
            self.install_stack()
        elif button_id == "registry-start":
            self.start_stack()
        elif button_id == "registry-stop":
            self.stop_stack()
        elif button_id == "registry-disable":
            self.disable_stack()
        elif button_id == "registry-uninstall":
            self.uninstall_stack()

    def switch_category(self, category: str) -> None:
        """Switch between infrastructure and services"""
        self.current_category = category

        # Update button styles
        infra_btn = self.query_one("#registry-cat-infrastructure", Button)
        services_btn = self.query_one("#registry-cat-services", Button)

        if category == "infrastructure":
            infra_btn.variant = "primary"
            services_btn.variant = "default"
        else:
            infra_btn.variant = "default"
            services_btn.variant = "primary"

        self.refresh_registry()

    def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
        """Handle row selection"""
        if event.data_table.id != "registry-table":
            return

        self.selected_stack = str(event.row_key.value) if event.row_key else None
        self.update_selected_label()
        self.update_button_states()

    def update_selected_label(self) -> None:
        """Update the selected stack label"""
        try:
            label = self.query_one("#registry-selected-label", Label)
            if self.selected_stack:
                stack = self.stacks_data.get(self.selected_stack)
                if stack:
                    status_parts = []
                    if stack.installed:
                        status_parts.append("[green]installed[/]")
                        if stack.enabled:
                            status_parts.append("[cyan]enabled[/]")
                            if stack.running:
                                status_parts.append("[green]running[/]")
                            else:
                                status_parts.append("[yellow]stopped[/]")
                        else:
                            status_parts.append("[dim]disabled[/]")
                    else:
                        status_parts.append("[dim]not installed[/]")

                    status = " | ".join(status_parts)
                    label.update(f"Selected: [bold]{self.selected_stack}[/] - {status}")
                else:
                    label.update(f"Selected: [bold]{self.selected_stack}[/]")
            else:
                label.update("Selected: [dim]None[/]")
        except Exception:
            pass

    def update_button_states(self) -> None:
        """Enable/disable buttons based on stack state"""
        try:
            install_btn = self.query_one("#registry-install", Button)
            start_btn = self.query_one("#registry-start", Button)
            stop_btn = self.query_one("#registry-stop", Button)
            disable_btn = self.query_one("#registry-disable", Button)
            uninstall_btn = self.query_one("#registry-uninstall", Button)

            if not self.selected_stack:
                install_btn.disabled = True
                start_btn.disabled = True
                stop_btn.disabled = True
                disable_btn.disabled = True
                uninstall_btn.disabled = True
                return

            stack = self.stacks_data.get(self.selected_stack)
            if not stack:
                return

            # Install: enabled if not installed
            install_btn.disabled = stack.installed

            # Start: enabled if installed, enabled, and not running
            start_btn.disabled = not (stack.installed and stack.enabled and not stack.running)

            # Stop: enabled if running
            stop_btn.disabled = not stack.running

            # Disable: enabled if installed and enabled
            disable_btn.disabled = not (stack.installed and stack.enabled)

            # Uninstall: enabled if installed
            uninstall_btn.disabled = not stack.installed

        except Exception:
            pass

    @work(thread=True)
    def refresh_registry(self) -> None:
        """Refresh the registry table from GitHub"""
        from ..core.registry import RegistryManager

        try:
            stacks = RegistryManager.list_stacks(category=self.current_category)

            # Store stack data
            self.stacks_data = {s.name: s for s in stacks}

            # Update table in main thread
            self.app.call_from_thread(self._populate_table, stacks)

        except Exception as e:
            self.app.call_from_thread(
                self.app.notify,
                f"Failed to fetch registry: {e}",
                severity="error"
            )

    def _populate_table(self, stacks) -> None:
        """Populate the table with stacks (must be called from main thread)"""
        try:
            table = self.query_one("#registry-table", DataTable)
            table.clear(columns=True)

            table.add_column("Name", width=35, key="name")
            table.add_column("Status", width=15, key="status")
            table.add_column("Ports", width=20, key="ports")
            table.add_column("Description", width=40, key="description")

            for stack in stacks:
                # Display name - highlight external registry stacks
                display_name = stack.name
                if stack.registry != "default":
                    # External: registry-name -> [registry] name
                    parts = stack.name.split("-", 1)
                    if len(parts) == 2:
                        display_name = f"[cyan][{parts[0]}][/] {parts[1]}"

                # Status indicator
                if not stack.installed:
                    status = "[dim]Not installed[/]"
                elif not stack.enabled:
                    status = "[yellow]Disabled[/]"
                elif stack.running:
                    status = "[green]● Running[/]"
                else:
                    status = "[red]○ Stopped[/]"

                # Ports
                ports = ", ".join(str(p) for p in stack.ports[:4]) if stack.ports else "-"
                if len(stack.ports) > 4:
                    ports += f" (+{len(stack.ports) - 4})"

                # Description (truncate if too long)
                desc = stack.description[:40] if stack.description else "-"
                if len(stack.description) > 40:
                    desc = desc[:37] + "..."

                table.add_row(display_name, status, ports, desc, key=stack.name)

            # Reset selection
            self.selected_stack = None
            self.update_selected_label()
            self.update_button_states()

        except Exception as e:
            self.app.notify(f"Error populating table: {e}", severity="error")

    def install_stack(self) -> None:
        """Install the selected stack"""
        if not self.selected_stack:
            return

        stack = self.stacks_data.get(self.selected_stack)
        if not stack:
            return

        # Fetch .env.example to get env vars with defaults and descriptions
        self._fetch_and_show_env_dialog(stack.name)

    @work(thread=True)
    def _fetch_and_show_env_dialog(self, name: str) -> None:
        """Fetch .env.example and show dialog"""
        from ..core.registry import RegistryManager

        self.app.call_from_thread(
            self.app.notify,
            f"Fetching configuration for {name}...",
            severity="information"
        )

        env_vars_data = RegistryManager.fetch_env_example(name)

        if env_vars_data:
            # Show dialog with env vars
            def on_dialog_result(env_values):
                if env_values is not None:  # User didn't cancel
                    self._do_install(name, env_values)

            self.app.call_from_thread(
                self.app.push_screen,
                EnvVarsDialog(self.app, name, env_vars_data),
                on_dialog_result
            )
        else:
            # No env vars needed, install directly
            self._do_install(name, None)

    @work(thread=True)
    def _do_install(self, name: str, env_vars: dict | None) -> None:
        """Perform the actual installation"""
        from ..core.registry import RegistryManager

        self.app.call_from_thread(
            self.app.notify,
            f"Installing {name}...",
            severity="information"
        )

        result = RegistryManager.install(name, env_vars)

        if result["success"]:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="information"
            )
        else:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="error"
            )

        # Refresh the table
        self.refresh_registry()

    @work(thread=True)
    def start_stack(self) -> None:
        """Start the selected stack"""
        if not self.selected_stack:
            return

        from ..core.registry import RegistryManager

        self.app.call_from_thread(
            self.app.notify,
            f"Starting {self.selected_stack}...",
            severity="information"
        )

        result = RegistryManager.start(self.selected_stack)

        if result["success"]:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="information"
            )
        else:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="error"
            )

        self.refresh_registry()

    @work(thread=True)
    def stop_stack(self) -> None:
        """Stop the selected stack"""
        if not self.selected_stack:
            return

        from ..core.registry import RegistryManager

        self.app.call_from_thread(
            self.app.notify,
            f"Stopping {self.selected_stack}...",
            severity="information"
        )

        result = RegistryManager.stop(self.selected_stack)

        if result["success"]:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="information"
            )
        else:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="error"
            )

        self.refresh_registry()

    @work(thread=True)
    def disable_stack(self) -> None:
        """Disable the selected stack"""
        if not self.selected_stack:
            return

        from ..core.registry import RegistryManager

        result = RegistryManager.disable(self.selected_stack)

        if result["success"]:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="information"
            )
        else:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="error"
            )

        self.refresh_registry()

    @work(thread=True)
    def uninstall_stack(self) -> None:
        """Uninstall the selected stack"""
        if not self.selected_stack:
            return

        from ..core.registry import RegistryManager

        result = RegistryManager.uninstall(self.selected_stack)

        if result["success"]:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="information"
            )
        else:
            self.app.call_from_thread(
                self.app.notify,
                result["message"],
                severity="error"
            )

        self.refresh_registry()
