"""
MiniMax TUI Application

Main Textual application class that provides a rich terminal user interface
for the MiniMax CLI. Includes header with logo, status, breadcrumb navigation,
footer with key bindings, command palette, and application lifecycle management.
"""

import argparse
import asyncio
import logging
from typing import Optional, Dict, Any, Type
from pathlib import Path

try:
    from textual.app import App, ComposeResult
    from textual.binding import Binding
    from textual.containers import Container, Horizontal, Vertical
    from textual.screen import Screen, ModalScreen
    from textual.widgets import (
        Header, Footer, Static, Button, Input, Label,
        OptionList, LoadingIndicator
    )
    from textual.reactive import reactive
    from textual.message import Message
    from textual.command import Provider, Hit, DiscoveryHit
    from textual import events, on
    from rich.text import Text
    from rich.panel import Panel
    from rich.align import Align

    # theme integration
    from .theme import (
        get_css_variables, get_color, get_icon, set_theme, get_theme_config
    )

    TEXTUAL_AVAILABLE = True
except ImportError:
    # Fallback classes for when Textual is not available
    class App:
        def __init__(self, *args, **kwargs):
            pass
        def run(self):
            raise ImportError("Textual is not installed. Install with: pip install minimax-client[ui]")

    class Screen:
        pass

    class ModalScreen:
        pass

    class ComposeResult:
        pass
    
    # Add fallback classes for widgets
    class Static:
        def __init__(self, *args, **kwargs):
            pass
    
    class Container:
        def __init__(self, *args, **kwargs):
            pass
    
    class Button:
        def __init__(self, *args, **kwargs):
            pass
    
    class Label:
        def __init__(self, *args, **kwargs):
            pass
    
    class OptionList:
        def __init__(self, *args, **kwargs):
            pass
        class OptionSelected:
            def __init__(self, *args, **kwargs):
                self.option = None
    
    class Provider:
        def __init__(self, *args, **kwargs):
            pass
    
    class Hit:
        def __init__(self, *args, **kwargs):
            pass
    
    class DiscoveryHit:
        def __init__(self, *args, **kwargs):
            pass
    
    class Binding:
        def __init__(self, *args, **kwargs):
            pass
    
    class Message:
        def __init__(self, *args, **kwargs):
            pass
    
    # Add reactive as a function
    def reactive(default, **kwargs):
        return default
    
    # Add Rich fallback classes
    class Text:
        def __init__(self, *args, **kwargs):
            pass
        def append(self, *args, **kwargs):
            pass
    
    class Panel:
        def __init__(self, *args, **kwargs):
            pass
    
    class Align:
        @staticmethod
        def center(*args, **kwargs):
            return None
    
    # Mock Input.Changed for type hints
    class Input:
        def __init__(self, *args, **kwargs):
            pass
        class Changed:
            def __init__(self, *args, **kwargs):
                self.value = ""

    def get_icon(name): return "•"
    def get_color(name, opacity=None): return "white"
    def set_theme(theme): pass
    def get_theme_config(): return None

    TEXTUAL_AVAILABLE = False


class MiniMaxHeader(Static):
    """Custom header widget with MiniMax logo, connection status, and breadcrumb."""
    connection_status = reactive("Disconnected", layout=True)
    model_name = reactive("", layout=True)
    screen_name = reactive("welcome", layout=True)

    def compose(self) -> ComposeResult:
        """Create the header layout with logo, status, and breadcrumb."""
        with Container(id="header-container"):
            yield Static(self._create_logo(), id="logo")
            yield Static(self._create_status(), id="status")
            yield Static(self._create_breadcrumb(), id="breadcrumb")

    def _create_logo(self) -> Text:
        logo = Text()
        logo.append(get_icon("chat"), style="bold " + get_color("primary"))
        logo.append(" MiniMax", style="bold white")
        return logo

    def _create_status(self) -> Text:
        status = Text()
        icon = "●"
        if self.connection_status == "Connected":
            status.append(f"{icon} ", style="bold " + get_color("success"))
            status.append("Connected", style=get_color("success"))
            if self.model_name:
                status.append(f" ({self.model_name})", style="dim")
        else:
            status.append(f"{icon} ", style="bold " + get_color("error"))
            status.append("Disconnected", style=get_color("error"))
        return status

    def _create_breadcrumb(self) -> Text:
        crumb = Text()
        crumb_icon = get_icon(self.screen_name) or "→"
        crumb.append(f"{crumb_icon} ", style=get_color("accent"))
        crumb.append(self.screen_name.title(), style="bold " + get_color("accent"))
        return crumb

    def watch_connection_status(self, _: str) -> None:
        self.query_one("#status", Static).update(self._create_status())

    def watch_model_name(self, _: str) -> None:
        self.query_one("#status", Static).update(self._create_status())

    def watch_screen_name(self, _: str) -> None:
        self.query_one("#breadcrumb", Static).update(self._create_breadcrumb())


class CommandPalette(ModalScreen):
    """Command palette for quick command access."""
    def __init__(self, commands: Dict[str, str]) -> None:
        super().__init__()
        self.commands = commands

    def compose(self) -> ComposeResult:
        """Create the command palette layout."""
        with Container(id="command-palette"):
            yield Label("Command Palette (Ctrl+P)", id="palette-title")
            yield Input(placeholder="Search commands...", id="command-input")
            yield OptionList(*[f"{cmd} — {desc}" for cmd, desc in self.commands.items()], id="command-list")

    def on_input_changed(self, event: Input.Changed) -> None:
        search = event.value.lower()
        option_list = self.query_one(OptionList)
        option_list.clear_options()
        for cmd, desc in self.commands.items():
            if search in cmd.lower() or search in desc.lower():
                option_list.add_option(f"{cmd} — {desc}")

    def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None:
        if event.option:
            command = str(event.option.prompt).split("—")[0].strip()
            self.app.post_message(CommandSelected(command))
            self.dismiss()

    def on_key(self, event) -> None:
        if event.key == "escape":
            self.dismiss()


class CommandSelected(Message):
    """Message sent when a command is selected from the palette."""
    def __init__(self, command: str) -> None:
        super().__init__()
        self.command = command


class WelcomeScreen(Screen):
    """Welcome screen shown when no specific command is provided."""
    BINDINGS = [
        Binding("c", "start_chat", "Chat"),
        Binding("a", "analyze", "Analyze"),
        Binding("g", "generate", "Generate"),
        Binding("e", "edit", "Edit"),
        Binding("p", "project", "Project"),
        Binding("ctrl+p", "command_palette", "Command Palette"),
        Binding("q", "quit", "Quit"),
    ]

    def compose(self) -> ComposeResult:
        with Container(id="welcome-container"):
            yield Static(self._create_welcome_text(), id="welcome-text")
            yield Container(
                Button(f"{get_icon('chat')} Chat", id="chat-btn", variant="primary"),
                Button(f"{get_icon('analyze')} Analyze", id="analyze-btn", variant="primary"),
                Button(f"{get_icon('generate')} Generate", id="generate-btn", variant="primary"),
                Button(f"{get_icon('edit')} Edit", id="edit-btn", variant="primary"),
                Button(f"{get_icon('project')} Project", id="project-btn", variant="primary"),
                id="action-buttons"
            )

    def _create_welcome_text(self) -> Panel:
        content = Text()
        content.append("🤖 Welcome to MiniMax Code Assistant\n\n", style="bold " + get_color("primary"))
        content.append("Select an action or press Ctrl+P to open the command palette.", style="dim")
        return Panel(Align.center(content), border_style=get_color("accent"))

    def on_button_pressed(self, event) -> None:
        mapping = {
            "chat-btn": "start_chat",
            "analyze-btn": "analyze",
            "generate-btn": "generate",
            "edit-btn": "edit",
            "project-btn": "project"
        }
        action = mapping.get(event.button.id)
        if action:
            getattr(self, f"action_{action}")()

    def action_start_chat(self) -> None: self.app.switch_screen("chat")
    def action_analyze(self) -> None: self.app.switch_screen("analyze")
    def action_generate(self) -> None: self.app.switch_screen("generate")
    def action_edit(self) -> None: self.app.switch_screen("edit")
    def action_project(self) -> None: self.app.switch_screen("project")
    def action_command_palette(self) -> None: self.app.show_command_palette()
    def action_quit(self) -> None: self.app.exit()


class MiniMaxCommandProvider(Provider):
    """Command provider for the command palette."""
    def __init__(self, app: "MiniMaxApp") -> None:
        super().__init__()
        self.app = app

    async def search(self, query: str) -> list[Hit]:
        commands = {
            "chat": "Start interactive chat session",
            "analyze": "Analyze code files and projects",
            "generate": "Generate new code",
            "edit": "Edit and modify files",
            "project": "Project-level operations",
            "help": "Show help information",
            "quit": "Exit application"
        }
        hits: list[Hit] = []
        for cmd, desc in commands.items():
            if query.lower() in cmd.lower() or query.lower() in desc.lower():
                hits.append(Hit(
                    score=100 - len(cmd),
                    match_display=f"{cmd} — {desc}",
                    command=lambda c=cmd: self.app.handle_command(c),
                    help=desc
                ))
        return hits


class MiniMaxApp(App):
    """Main MiniMax TUI application."""
    CSS_PATH = str(Path(__file__).parent / "theme.css")

    BINDINGS = [
        Binding("ctrl+p", "command_palette", "Command Palette"),
        Binding("ctrl+q,ctrl+c", "quit", "Quit"),
        Binding("f1", "help", "Help"),
        Binding("ctrl+t", "toggle_theme", "Toggle Theme"),
    ]

    def __init__(
        self,
        client=None,
        config=None,
        args: Optional[argparse.Namespace] = None,
        **kwargs
    ):
        super().__init__(**kwargs)
        self.client = client
        self.config = config
        self.args = args or argparse.Namespace()
        self.logger = logging.getLogger(__name__)
        self.screen_classes: Dict[str, Type[Screen]] = {}
        self.commands = {
            "chat": "Interactive chat with AI",
            "analyze": "Analyze code files",
            "generate": "Generate code or templates",
            "edit": "Edit existing files",
            "project": "Project analysis and tools",
            "help": "Show help information",
            "quit": "Exit the application"
        }
        self.connection_status = "Disconnected"
        self.model_name = ""
        self._check_connection()

    def on_mount(self) -> None:
        self.title = "MiniMax Code Assistant"
        self.sub_title = "AI-Powered Development Tools"
        # install screens
        self._install_screens()
        # initial screen
        initial = self._determine_initial_screen()
        self.switch_screen(initial)
        # update header screen_name
        header = self.query_one(MiniMaxHeader)
        header.screen_name = initial

    def compose(self) -> ComposeResult:
        yield MiniMaxHeader()
        yield Container(id="main-content")
        yield Footer()

    def _install_screens(self) -> None:
        self.install_screen(WelcomeScreen(), name="welcome")
        modules = {
            "chat": "minimax_client.ui.screens.chat",
            "analyze": "minimax_client.ui.screens.analyze",
            "generate": "minimax_client.ui.screens.generate",
            "edit": "minimax_client.ui.screens.edit",
            "project": "minimax_client.ui.screens.project"
        }
        for name, path in modules.items():
            try:
                parts = path.split('.')
                module = __import__(path, fromlist=[parts[-1]])
                cls_name = f"{name.title()}Screen"
                if hasattr(module, cls_name):
                    cls = getattr(module, cls_name)
                    inst = cls(client=self.client, config=self.config, args=self.args)
                    self.install_screen(inst, name=name)
                    self.screen_classes[name] = cls
            except ImportError as e:
                self.logger.warning(f"{name} screen unavailable: {e}")
            except Exception as e:
                self.logger.error(f"Error loading {name} screen: {e}")

    def _determine_initial_screen(self) -> str:
        cmd = getattr(self.args, 'command', None)
        return cmd if cmd in self.screen_classes else "welcome"

    def _check_connection(self) -> None:
        try:
            if self.client:
                self.connection_status = "Connected"
                self.model_name = getattr(self.config, 'model', "default")
            else:
                self.connection_status = "Disconnected"
                self.model_name = ""
        except Exception as e:
            self.logger.warning(f"Connection check error: {e}")
            self.connection_status = "Error"
            self.model_name = ""
        try:
            hdr = self.query_one(MiniMaxHeader)
            hdr.connection_status = self.connection_status
            hdr.model_name = self.model_name
        except:
            pass

    def action_command_palette(self) -> None:
        self.show_command_palette()

    def show_command_palette(self) -> None:
        self.push_screen(CommandPalette(self.commands))

    def on_command_selected(self, msg: CommandSelected) -> None:
        self.handle_command(msg.command)

    def handle_command(self, cmd: str) -> None:
        if cmd in self.screen_classes:
            self.switch_screen(cmd)
        elif cmd == "help":
            self.action_help()
        elif cmd == "quit":
            self.exit()
        else:
            self.logger.warning(f"Unknown command: {cmd}")

    def action_help(self) -> None:
        help_text = """
MiniMax TUI Help:

Ctrl+P  — Open command palette
Ctrl+T  — Toggle theme
Ctrl+Q  — Quit
F1      — Help
        """
        class HelpModal(ModalScreen):
            def compose(self) -> ComposeResult:
                with Container(id="help-container"):
                    yield Static(help_text, id="help-text")
                    yield Button("Close", id="close-help")
            def on_button_pressed(self, ev):
                if ev.button.id == "close-help":
                    self.dismiss()
        self.push_screen(HelpModal())

    def action_quit(self) -> None:
        self.exit()

    def action_toggle_theme(self) -> None:
        current = get_theme_config().mode.value
        new = "light" if current == "dark" else "dark"
        set_theme(new)
        # reload CSS and update header
        self.refresh_css()
        try:
            hdr = self.query_one(MiniMaxHeader)
            hdr.screen_name = hdr.screen_name  # trigger update
        except:
            pass

    async def on_shutdown_request(self, event) -> None:
        try:
            self.logger.info("Shutting down MiniMax TUI")
        except:
            pass
        event.prevent_default = False

    def switch_screen(self, name: str) -> None:
        try:
            if name in self.screen_classes or name == "welcome":
                super().switch_screen(name)
            else:
                self.logger.warning(f"Screen '{name}' not found, falling back")
                super().switch_screen("welcome")
            hdr = self.query_one(MiniMaxHeader)
            hdr.screen_name = name
        except Exception as e:
            self.logger.error(f"Switch screen error: {e}")
            try:
                super().switch_screen("welcome")
            except:
                pass


__all__ = ["MiniMaxApp"]