"""BIOS-style TUI for SmartTools using snack (python3-newt)."""

import sys
# Ensure system packages are accessible
if '/usr/lib/python3/dist-packages' not in sys.path:
    sys.path.insert(0, '/usr/lib/python3/dist-packages')

import snack
from typing import Optional, List, Tuple

from .tool import (
    Tool, ToolArgument, PromptStep, CodeStep, Step,
    list_tools, load_tool, save_tool, delete_tool, tool_exists
)
from .providers import Provider, load_providers, add_provider, delete_provider, get_provider


class SmartToolsUI:
    """BIOS-style UI for SmartTools."""

    def __init__(self):
        self.screen = None

    def run(self):
        """Run the UI."""
        self.screen = snack.SnackScreen()
        # Enable mouse support
        self.screen.pushHelpLine(" Tab/Arrow:Navigate | Enter:Select | Mouse:Click | Esc:Back ")
        try:
            # Enable mouse - newt supports GPM and xterm mouse
            import os
            os.environ.setdefault('NEWT_MONO', '0')
            self.main_menu()
        finally:
            self.screen.finish()

    def main_menu(self):
        """Show the main menu."""
        while True:
            items = [
                ("Create New Tool", "create"),
                ("Edit Tool", "edit"),
                ("Delete Tool", "delete"),
                ("List Tools", "list"),
                ("Test Tool", "test"),
                ("Manage Providers", "providers"),
                ("Exit", "exit"),
            ]

            listbox = snack.Listbox(height=7, width=30, returnExit=1)
            for label, value in items:
                listbox.append(label, value)

            grid = snack.GridForm(self.screen, "SmartTools Manager", 1, 1)
            grid.add(listbox, 0, 0)

            result = grid.runOnce()
            selected = listbox.current()

            if selected == "exit" or result == "ESC":
                break
            elif selected == "create":
                self.tool_builder(None)
            elif selected == "edit":
                self.select_and_edit_tool()
            elif selected == "delete":
                self.select_and_delete_tool()
            elif selected == "list":
                self.show_tools_list()
            elif selected == "test":
                self.select_and_test_tool()
            elif selected == "providers":
                self.manage_providers()

    def message_box(self, title: str, message: str):
        """Show a message box."""
        snack.ButtonChoiceWindow(self.screen, title, message, ["OK"])

    def yes_no(self, title: str, message: str) -> bool:
        """Show a yes/no dialog."""
        result = snack.ButtonChoiceWindow(self.screen, title, message, ["Yes", "No"])
        return result == "yes"

    def input_box(self, title: str, prompt: str, initial: str = "", width: int = 40) -> Optional[str]:
        """Show an input dialog."""
        entry = snack.Entry(width, initial)
        grid = snack.GridForm(self.screen, title, 1, 3)
        grid.add(snack.Label(prompt), 0, 0)
        grid.add(entry, 0, 1, padding=(0, 1, 0, 1))

        buttons = snack.ButtonBar(self.screen, [("OK", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 2)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            return entry.value()
        return None

    def text_edit(self, title: str, initial: str = "", width: int = 60, height: int = 10) -> Optional[str]:
        """Show a multi-line text editor."""
        text = snack.Textbox(width, height, initial, scroll=1, wrap=1)

        # snack doesn't have a true multi-line editor, so we use Entry for now
        # For multi-line, we'll use a workaround with a simple entry
        entry = snack.Entry(width, initial, scroll=1)

        grid = snack.GridForm(self.screen, title, 1, 2)
        grid.add(entry, 0, 0, padding=(0, 0, 0, 1))

        buttons = snack.ButtonBar(self.screen, [("OK", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 1)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            return entry.value()
        return None

    def select_provider(self) -> Optional[str]:
        """Show provider selection dialog."""
        providers = load_providers()

        listbox = snack.Listbox(height=min(len(providers) + 1, 8), width=50, returnExit=1)
        for p in providers:
            listbox.append(f"{p.name}: {p.command}", p.name)
        listbox.append("[ + Add New Provider ]", "__new__")

        grid = snack.GridForm(self.screen, "Select Provider", 1, 2)
        grid.add(listbox, 0, 0)

        buttons = snack.ButtonBar(self.screen, [("Select", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 1)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "cancel" or result == "ESC":
            return None

        selected = listbox.current()

        if selected == "__new__":
            provider = self.add_provider_dialog()
            if provider:
                add_provider(provider)
                return provider.name
            return None

        return selected

    def add_provider_dialog(self) -> Optional[Provider]:
        """Dialog to add a new provider."""
        name_entry = snack.Entry(30, "")
        cmd_entry = snack.Entry(40, "")
        desc_entry = snack.Entry(40, "")

        grid = snack.GridForm(self.screen, "Add Provider", 2, 4)
        grid.add(snack.Label("Name:"), 0, 0, anchorLeft=1)
        grid.add(name_entry, 1, 0, padding=(1, 0, 0, 0))
        grid.add(snack.Label("Command:"), 0, 1, anchorLeft=1)
        grid.add(cmd_entry, 1, 1, padding=(1, 0, 0, 0))
        grid.add(snack.Label("Description:"), 0, 2, anchorLeft=1)
        grid.add(desc_entry, 1, 2, padding=(1, 0, 0, 0))

        buttons = snack.ButtonBar(self.screen, [("OK", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 3, growx=1, growy=1)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            name = name_entry.value().strip()
            cmd = cmd_entry.value().strip()
            if name and cmd:
                return Provider(name=name, command=cmd, description=desc_entry.value().strip())
            self.message_box("Error", "Name and command are required.")

        return None

    def add_argument_dialog(self, existing: Optional[ToolArgument] = None) -> Optional[ToolArgument]:
        """Dialog to add/edit an argument."""
        flag_entry = snack.Entry(20, existing.flag if existing else "--")
        var_entry = snack.Entry(20, existing.variable if existing else "")
        default_entry = snack.Entry(20, existing.default or "" if existing else "")
        desc_entry = snack.Entry(40, existing.description if existing else "")

        title = "Edit Argument" if existing else "Add Argument"
        grid = snack.GridForm(self.screen, title, 2, 5)
        grid.add(snack.Label("Flag:"), 0, 0, anchorLeft=1)
        grid.add(flag_entry, 1, 0, padding=(1, 0, 0, 0))
        grid.add(snack.Label("Variable:"), 0, 1, anchorLeft=1)
        grid.add(var_entry, 1, 1, padding=(1, 0, 0, 0))
        grid.add(snack.Label("Default:"), 0, 2, anchorLeft=1)
        grid.add(default_entry, 1, 2, padding=(1, 0, 0, 0))
        grid.add(snack.Label("Description:"), 0, 3, anchorLeft=1)
        grid.add(desc_entry, 1, 3, padding=(1, 0, 0, 0))

        buttons = snack.ButtonBar(self.screen, [("OK", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 4, growx=1)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            flag = flag_entry.value().strip()
            var = var_entry.value().strip()

            if not flag:
                self.message_box("Error", "Flag is required.")
                return None

            if not var:
                var = flag.lstrip("-").replace("-", "_")

            return ToolArgument(
                flag=flag,
                variable=var,
                default=default_entry.value().strip() or None,
                description=desc_entry.value().strip()
            )

        return None

    def add_step_dialog(self, tool: Tool, existing_step: Optional[Step] = None, step_idx: int = -1) -> Optional[Step]:
        """Dialog to choose and add a step."""
        if existing_step:
            # Edit existing step
            if isinstance(existing_step, PromptStep):
                return self.add_prompt_dialog(tool, existing_step, step_idx)
            else:
                return self.add_code_dialog(tool, existing_step, step_idx)

        # Choose step type
        listbox = snack.Listbox(height=2, width=30, returnExit=1)
        listbox.append("Prompt (AI call)", "prompt")
        listbox.append("Code (Python)", "code")

        grid = snack.GridForm(self.screen, "Add Step", 1, 2)
        grid.add(listbox, 0, 0)

        buttons = snack.ButtonBar(self.screen, [("Select", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 1)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "cancel" or result == "ESC":
            return None

        step_type = listbox.current()

        if step_type == "prompt":
            return self.add_prompt_dialog(tool, None, step_idx)
        else:
            return self.add_code_dialog(tool, None, step_idx)

    def get_available_variables(self, tool: Tool, up_to_step: int = -1) -> List[str]:
        """Get available variables at a point in the tool."""
        variables = ["input"]
        for arg in tool.arguments:
            variables.append(arg.variable)
        if up_to_step == -1:
            up_to_step = len(tool.steps)
        for i, step in enumerate(tool.steps):
            if i >= up_to_step:
                break
            variables.append(step.output_var)
        return variables

    def add_prompt_dialog(self, tool: Tool, existing: Optional[PromptStep] = None, step_idx: int = -1) -> Optional[PromptStep]:
        """Dialog to add/edit a prompt step."""
        available = self.get_available_variables(tool, step_idx if step_idx >= 0 else -1)
        var_help = "Variables: " + ", ".join(f"{{{v}}}" for v in available)

        # Provider selection first
        provider = self.select_provider()
        if not provider:
            provider = existing.provider if existing else "mock"

        prompt_entry = snack.Entry(60, existing.prompt if existing else f"Process this:\n\n{{input}}", scroll=1)
        output_entry = snack.Entry(20, existing.output_var if existing else "result")

        title = "Edit Prompt Step" if existing else "Add Prompt Step"
        grid = snack.GridForm(self.screen, title, 2, 4)

        grid.add(snack.Label(f"Provider: {provider}"), 0, 0, anchorLeft=1, growx=1)
        grid.add(snack.Label(""), 1, 0)

        grid.add(snack.Label(f"Prompt ({var_help}):"), 0, 1, anchorLeft=1, growx=1)
        grid.add(snack.Label(""), 1, 1)

        grid.add(prompt_entry, 0, 2, growx=1)
        grid.add(snack.Label(""), 1, 2)

        sub_grid = snack.Grid(2, 1)
        sub_grid.setField(snack.Label("Output var:"), 0, 0, anchorLeft=1)
        sub_grid.setField(output_entry, 1, 0, padding=(1, 0, 0, 0))
        grid.add(sub_grid, 0, 3, anchorLeft=1)

        buttons = snack.ButtonBar(self.screen, [("OK", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 1, 3)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            prompt = prompt_entry.value().strip()
            output_var = output_entry.value().strip()

            if not prompt:
                self.message_box("Error", "Prompt is required.")
                return None
            if not output_var:
                output_var = "result"

            return PromptStep(prompt=prompt, provider=provider, output_var=output_var)

        return None

    def add_code_dialog(self, tool: Tool, existing: Optional[CodeStep] = None, step_idx: int = -1) -> Optional[CodeStep]:
        """Dialog to add/edit a code step."""
        available = self.get_available_variables(tool, step_idx if step_idx >= 0 else -1)
        var_help = "Variables: " + ", ".join(available)

        default_code = existing.code if existing else "# Set 'result' for output\nresult = input.upper()"
        code_entry = snack.Entry(60, default_code, scroll=1)
        output_entry = snack.Entry(20, existing.output_var if existing else "processed")

        title = "Edit Code Step" if existing else "Add Code Step"
        grid = snack.GridForm(self.screen, title, 2, 4)

        grid.add(snack.Label(f"Python Code ({var_help}):"), 0, 0, anchorLeft=1, growx=1)
        grid.add(snack.Label("Set 'result' variable for output"), 1, 0)

        grid.add(code_entry, 0, 1, growx=1)
        grid.add(snack.Label(""), 1, 1)

        sub_grid = snack.Grid(2, 1)
        sub_grid.setField(snack.Label("Output var:"), 0, 0, anchorLeft=1)
        sub_grid.setField(output_entry, 1, 0, padding=(1, 0, 0, 0))
        grid.add(sub_grid, 0, 2, anchorLeft=1)

        buttons = snack.ButtonBar(self.screen, [("OK", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 1, 2)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            code = code_entry.value().strip()
            output_var = output_entry.value().strip()

            if not code:
                self.message_box("Error", "Code is required.")
                return None
            if not output_var:
                output_var = "processed"

            return CodeStep(code=code, output_var=output_var)

        return None

    def tool_builder(self, existing: Optional[Tool] = None) -> Optional[Tool]:
        """Main tool builder - BIOS-style unified form."""
        is_edit = existing is not None

        # Initialize tool
        if existing:
            tool = Tool(
                name=existing.name,
                description=existing.description,
                arguments=list(existing.arguments),
                steps=list(existing.steps),
                output=existing.output
            )
        else:
            tool = Tool(name="", description="", arguments=[], steps=[], output="{input}")

        while True:
            # Create form elements
            name_entry = snack.Entry(25, tool.name, scroll=0)
            desc_entry = snack.Entry(25, tool.description, scroll=1)
            output_entry = snack.Entry(25, tool.output, scroll=1)

            # Arguments listbox
            args_listbox = snack.Listbox(height=4, width=35, returnExit=0, scroll=1)
            for i, arg in enumerate(tool.arguments):
                args_listbox.append(f"{arg.flag} -> {{{arg.variable}}}", i)
            args_listbox.append("[ + Add ]", "add")

            # Steps listbox
            steps_listbox = snack.Listbox(height=5, width=35, returnExit=0, scroll=1)
            for i, step in enumerate(tool.steps):
                if isinstance(step, PromptStep):
                    steps_listbox.append(f"P:{step.provider} -> {{{step.output_var}}}", i)
                else:
                    steps_listbox.append(f"C: -> {{{step.output_var}}}", i)
            steps_listbox.append("[ + Add ]", "add")

            # Build the grid layout using nested grids for better control
            title = f"Edit Tool: {tool.name}" if is_edit and tool.name else "New Tool"

            # Left column grid: Name, Description, Output
            left_grid = snack.Grid(1, 6)
            left_grid.setField(snack.Label("Name:"), 0, 0, anchorLeft=1)
            left_grid.setField(name_entry, 0, 1, anchorLeft=1)
            left_grid.setField(snack.Label("Description:"), 0, 2, anchorLeft=1, padding=(0, 1, 0, 0))
            left_grid.setField(desc_entry, 0, 3, anchorLeft=1)
            left_grid.setField(snack.Label("Output:"), 0, 4, anchorLeft=1, padding=(0, 1, 0, 0))
            left_grid.setField(output_entry, 0, 5, anchorLeft=1)

            # Right column grid: Arguments and Steps
            right_grid = snack.Grid(1, 4)
            right_grid.setField(snack.Label("Arguments:"), 0, 0, anchorLeft=1)
            right_grid.setField(args_listbox, 0, 1, anchorLeft=1)
            right_grid.setField(snack.Label("Execution Steps:"), 0, 2, anchorLeft=1, padding=(0, 1, 0, 0))
            right_grid.setField(steps_listbox, 0, 3, anchorLeft=1)

            # Main grid
            grid = snack.GridForm(self.screen, title, 2, 2)
            grid.add(left_grid, 0, 0, anchorTop=1, padding=(0, 0, 2, 0))
            grid.add(right_grid, 1, 0, anchorTop=1)

            # Buttons at bottom
            buttons = snack.ButtonBar(self.screen, [("Save", "save"), ("Cancel", "cancel")])
            grid.add(buttons, 0, 1, growx=1)

            # Handle hotkeys for listbox interaction
            form = grid.form

            while True:
                result = form.run()

                # Update tool from entries
                if not is_edit:
                    tool.name = name_entry.value().strip()
                tool.description = desc_entry.value().strip()
                tool.output = output_entry.value().strip()

                # Check what was activated
                if result == args_listbox:
                    selected = args_listbox.current()
                    if selected == "add":
                        new_arg = self.add_argument_dialog()
                        if new_arg:
                            tool.arguments.append(new_arg)
                        break  # Refresh form
                    elif isinstance(selected, int):
                        # Edit/delete existing argument
                        action = self.arg_action_menu(tool.arguments[selected])
                        if action == "edit":
                            updated = self.add_argument_dialog(tool.arguments[selected])
                            if updated:
                                tool.arguments[selected] = updated
                        elif action == "delete":
                            tool.arguments.pop(selected)
                        break  # Refresh form

                elif result == steps_listbox:
                    selected = steps_listbox.current()
                    if selected == "add":
                        new_step = self.add_step_dialog(tool)
                        if new_step:
                            tool.steps.append(new_step)
                        break  # Refresh form
                    elif isinstance(selected, int):
                        # Edit/delete existing step
                        action = self.step_action_menu(tool.steps[selected], selected, len(tool.steps))
                        if action == "edit":
                            updated = self.add_step_dialog(tool, tool.steps[selected], selected)
                            if updated:
                                tool.steps[selected] = updated
                        elif action == "delete":
                            tool.steps.pop(selected)
                        elif action == "move_up" and selected > 0:
                            tool.steps[selected], tool.steps[selected-1] = tool.steps[selected-1], tool.steps[selected]
                        elif action == "move_down" and selected < len(tool.steps) - 1:
                            tool.steps[selected], tool.steps[selected+1] = tool.steps[selected+1], tool.steps[selected]
                        break  # Refresh form

                elif buttons.buttonPressed(result) == "save":
                    if not tool.name:
                        self.message_box("Error", "Tool name is required.")
                        break
                    if not is_edit and tool_exists(tool.name):
                        if not self.yes_no("Overwrite?", f"Tool '{tool.name}' exists. Overwrite?"):
                            break
                    self.screen.popWindow()
                    save_tool(tool)
                    self.message_box("Success", f"Tool '{tool.name}' saved!")
                    return tool

                elif buttons.buttonPressed(result) == "cancel" or result == "ESC":
                    self.screen.popWindow()
                    return None

                else:
                    # Tab between fields, continue
                    continue

            self.screen.popWindow()

    def arg_action_menu(self, arg: ToolArgument) -> Optional[str]:
        """Show action menu for an argument."""
        listbox = snack.Listbox(height=3, width=20, returnExit=1)
        listbox.append("Edit", "edit")
        listbox.append("Delete", "delete")
        listbox.append("Cancel", "cancel")

        grid = snack.GridForm(self.screen, f"Argument: {arg.flag}", 1, 1)
        grid.add(listbox, 0, 0)

        grid.runOnce()
        return listbox.current() if listbox.current() != "cancel" else None

    def step_action_menu(self, step: Step, idx: int, total: int) -> Optional[str]:
        """Show action menu for a step."""
        step_type = "Prompt" if isinstance(step, PromptStep) else "Code"

        items = [("Edit", "edit")]
        if idx > 0:
            items.append(("Move Up", "move_up"))
        if idx < total - 1:
            items.append(("Move Down", "move_down"))
        items.append(("Delete", "delete"))
        items.append(("Cancel", "cancel"))

        listbox = snack.Listbox(height=len(items), width=20, returnExit=1)
        for label, value in items:
            listbox.append(label, value)

        grid = snack.GridForm(self.screen, f"Step {idx+1}: {step_type}", 1, 1)
        grid.add(listbox, 0, 0)

        grid.runOnce()
        return listbox.current() if listbox.current() != "cancel" else None

    def select_and_edit_tool(self):
        """Select a tool to edit."""
        tools = list_tools()
        if not tools:
            self.message_box("Edit Tool", "No tools found.")
            return

        listbox = snack.Listbox(height=min(len(tools), 10), width=40, returnExit=1, scroll=1)
        for name in tools:
            tool = load_tool(name)
            desc = tool.description[:30] if tool and tool.description else "No description"
            listbox.append(f"{name}: {desc}", name)

        grid = snack.GridForm(self.screen, "Select Tool to Edit", 1, 2)
        grid.add(listbox, 0, 0)
        buttons = snack.ButtonBar(self.screen, [("Select", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 1)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            selected = listbox.current()
            tool = load_tool(selected)
            if tool:
                self.tool_builder(tool)

    def select_and_delete_tool(self):
        """Select a tool to delete."""
        tools = list_tools()
        if not tools:
            self.message_box("Delete Tool", "No tools found.")
            return

        listbox = snack.Listbox(height=min(len(tools), 10), width=40, returnExit=1, scroll=1)
        for name in tools:
            listbox.append(name, name)

        grid = snack.GridForm(self.screen, "Select Tool to Delete", 1, 2)
        grid.add(listbox, 0, 0)
        buttons = snack.ButtonBar(self.screen, [("Delete", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 1)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            selected = listbox.current()
            if self.yes_no("Confirm", f"Delete tool '{selected}'?"):
                if delete_tool(selected):
                    self.message_box("Deleted", f"Tool '{selected}' deleted.")

    def show_tools_list(self):
        """Show list of all tools."""
        tools = list_tools()
        if not tools:
            self.message_box("Tools", "No tools found.\n\nCreate one from the main menu.")
            return

        text = ""
        for name in tools:
            tool = load_tool(name)
            if tool:
                text += f"{name}\n"
                text += f"  {tool.description or 'No description'}\n"
                if tool.arguments:
                    args = ", ".join(a.flag for a in tool.arguments)
                    text += f"  Args: {args}\n"
                if tool.steps:
                    steps = []
                    for s in tool.steps:
                        if isinstance(s, PromptStep):
                            steps.append(f"P:{s.provider}")
                        else:
                            steps.append("C")
                    text += f"  Steps: {' -> '.join(steps)}\n"
                text += "\n"

        snack.ButtonChoiceWindow(self.screen, "Available Tools", text.strip(), ["OK"])

    def select_and_test_tool(self):
        """Select a tool to test."""
        tools = list_tools()
        if not tools:
            self.message_box("Test Tool", "No tools found.")
            return

        listbox = snack.Listbox(height=min(len(tools), 10), width=40, returnExit=1, scroll=1)
        for name in tools:
            listbox.append(name, name)

        grid = snack.GridForm(self.screen, "Select Tool to Test", 1, 2)
        grid.add(listbox, 0, 0)
        buttons = snack.ButtonBar(self.screen, [("Test", "ok"), ("Cancel", "cancel")])
        grid.add(buttons, 0, 1)

        result = grid.runOnce()

        if buttons.buttonPressed(result) == "ok":
            selected = listbox.current()
            tool = load_tool(selected)
            if tool:
                test_input = self.input_box("Test Input", "Enter test input:", "Hello world")
                if test_input:
                    from .runner import run_tool
                    output, code = run_tool(
                        tool=tool,
                        input_text=test_input,
                        custom_args={},
                        provider_override="mock",
                        dry_run=False,
                        show_prompt=False,
                        verbose=False
                    )
                    result_text = f"Exit code: {code}\n\nOutput:\n{output[:500]}"
                    self.message_box("Test Result", result_text)

    def manage_providers(self):
        """Manage providers menu."""
        while True:
            providers = load_providers()

            listbox = snack.Listbox(height=min(len(providers) + 2, 10), width=50, returnExit=1, scroll=1)
            for p in providers:
                listbox.append(f"{p.name}: {p.command}", p.name)
            listbox.append("[ + Add Provider ]", "__add__")
            listbox.append("[ <- Back ]", "__back__")

            grid = snack.GridForm(self.screen, "Manage Providers", 1, 1)
            grid.add(listbox, 0, 0)

            grid.runOnce()
            selected = listbox.current()

            if selected == "__back__":
                break
            elif selected == "__add__":
                provider = self.add_provider_dialog()
                if provider:
                    add_provider(provider)
                    self.message_box("Success", f"Provider '{provider.name}' added.")
            else:
                # Edit or delete
                provider = get_provider(selected)
                if provider:
                    action = self.provider_action_menu(provider)
                    if action == "edit":
                        updated = self.add_provider_dialog()  # TODO: pass existing
                        if updated:
                            add_provider(updated)
                    elif action == "delete":
                        if self.yes_no("Confirm", f"Delete provider '{selected}'?"):
                            delete_provider(selected)

    def provider_action_menu(self, provider: Provider) -> Optional[str]:
        """Show action menu for a provider."""
        listbox = snack.Listbox(height=3, width=20, returnExit=1)
        listbox.append("Edit", "edit")
        listbox.append("Delete", "delete")
        listbox.append("Cancel", "cancel")

        grid = snack.GridForm(self.screen, f"Provider: {provider.name}", 1, 1)
        grid.add(listbox, 0, 0)

        grid.runOnce()
        return listbox.current() if listbox.current() != "cancel" else None


def run_ui():
    """Entry point for the snack UI."""
    ui = SmartToolsUI()
    ui.run()


if __name__ == "__main__":
    run_ui()
