"""Unified Alloy Runtime Terminal Application.

This module provides the main Textual application that serves as the unified TUI
for Alloy Runtime. It uses a screen-based architecture where each main view
(Chat, Agents, Templates, Content, Schemas) is a proper Textual Screen.

The app uses:
- Screen stack for navigation between main views
- AppStore for shared state following Textual's "App as Store" pattern
- Priority bindings for global navigation that work regardless of focus
"""

from typing import Literal

from textual.app import App

from cli.tui.app_store import AppStore
from cli.tui.chat.screen import ChatScreen
from cli.tui.screens.agents import AgentsScreen
from cli.tui.screens.content import ContentScreen
from cli.tui.screens.dashboard import DashboardScreen
from cli.tui.screens.schemas import SchemasScreen
from cli.tui.screens.templates import TemplatesScreen
from cli.tui.screens.tool_configs import ToolConfigsScreen
from cli.tui.widgets.status_footer import StatusFooter
from alloy_runtime_sdk.logging.config import get_logger

logger = get_logger(__name__)

SeverityLevel = Literal["information", "warning", "error"]


class AlloyRuntimeApp(App[None]):
    """Unified Alloy Runtime Terminal Application.

    A full-featured TUI that provides:
    - Screen-based navigation between major sections
    - Consistent keyboard shortcuts across all views (c/a/t/s/m for switching)
    - Integrated chat, browse, and create workflows
    - Simple shared store accessible via self.app.store

    Navigation:
    - c: Chat screen
    - a: Agents screen
    - t: Templates screen
    - m: Content (media) screen
    - s: Schemas screen
    - d: Dashboard overlay
    - ?: Help modal

    All screens inherit from NavScreen which provides these navigation bindings
    as priority bindings, ensuring they work regardless of focus state.
    """

    CSS_PATH = [
        "styles/app.tcss",
        "styles/browser.tcss",
        "styles/chat.tcss",
        "styles/modals.tcss",
        "styles/forms.tcss",
        "styles/dashboard.tcss",
    ]

    # No bindings at app level - all bindings are on screens
    # This avoids conflicts and ensures proper screen isolation
    BINDINGS = []

    # Register screens with the app
    SCREENS = {
        "chat": ChatScreen,
        "agents": AgentsScreen,
        "templates": TemplatesScreen,
        "content": ContentScreen,
        "schemas": SchemasScreen,
        "tool_configs": ToolConfigsScreen,
    }

    theme: str = "tokyo-night"  # type: ignore[assignment]

    def __init__(self, api_url: str, api_key: str):
        """Initialize the Alloy Runtime app.

        Args:
            api_url: Base API URL for the server
            api_key: API key for authentication
        """
        super().__init__()
        # Create the simple store - screens access via self.app.store
        self.store = AppStore(api_url=api_url, api_key=api_key)
        # Track current screen for navigation
        self._current_screen_id: str = "chat"
        logger.info("tui_app_initialized", api_url=api_url)

    def on_mount(self) -> None:
        """Set up initial state on startup."""
        logger.info("tui_app_mounted")
        # Push the dashboard screen first, then the chat screen
        # Dashboard will be shown as an overlay
        self.push_screen("chat")
        self.push_screen(DashboardScreen(), self._on_dashboard_dismiss)

    def _on_dashboard_dismiss(self, screen_id: str | None) -> None:
        """Handle dashboard dismissal by switching to the selected screen.

        Args:
            screen_id: The screen ID to navigate to (e.g., "chat", "agents"), or None if dismissed without selection
        """
        if screen_id is None:
            return

        # Extract just the screen name from tab-* format if needed
        if screen_id.startswith("tab-"):
            screen_id = screen_id[4:]  # Remove "tab-" prefix

        logger.info("dashboard_dismissed", target_screen=screen_id)
        self.switch_to_screen(screen_id)

    def switch_to_screen(self, screen_id: str) -> None:
        """Switch to a different screen.

        This method handles screen switching by:
        1. Popping the current screen
        2. Pushing the new screen

        Args:
            screen_id: The ID of the screen to switch to (chat, agents, templates, content, schemas)
        """
        if screen_id == self._current_screen_id:
            return  # Already on this screen

        if screen_id not in self.SCREENS:
            logger.warning("unknown_screen_id", screen_id=screen_id)
            return

        logger.info(
            "switching_screen", from_screen=self._current_screen_id, to_screen=screen_id
        )

        # Use switch_screen for clean transitions
        self._current_screen_id = screen_id
        self.switch_screen(screen_id)  # pyright: ignore[reportUnknownMemberType]

    def notify(
        self,
        message: str,
        *,
        title: str = "",
        severity: SeverityLevel = "information",
        timeout: float | None = None,
        markup: bool = True,
    ) -> None:
        """Show a notification in the status footer instead of a toast.

        This overrides the default App.notify() to route notifications
        to our vim-style StatusFooter widget if available.

        Args:
            message: The notification message
            title: Optional title (ignored for status bar)
            severity: One of "information", "warning", "error"
            timeout: Seconds before clearing (default varies by severity)
            markup: Whether message contains markup (ignored for status bar)
        """
        # Errors get longer display time (6s) so users can read them
        if timeout is not None:
            effective_timeout = timeout
        elif severity == "error":
            effective_timeout = 6.0
        else:
            effective_timeout = 2.0
        try:
            footer = self.screen.query_one(StatusFooter)
            footer.show_notification(
                message, severity=severity, timeout=effective_timeout
            )
        except Exception:
            # Fall back to parent if footer not found
            super().notify(
                message, title=title, severity=severity, timeout=timeout, markup=markup
            )

    async def on_unmount(self) -> None:
        """Clean up on app exit."""
        logger.info("tui_app_shutting_down")
        await self.store.close()
        logger.info("tui_app_shutdown_complete")


def run_app(api_url: str, api_key: str) -> None:
    """Run the Alloy Runtime Terminal app.

    Args:
        api_url: Base API URL for the server
        api_key: API key for authentication
    """
    logger.info("tui_app_starting", api_url=api_url)
    app = AlloyRuntimeApp(api_url=api_url, api_key=api_key)
    app.run()
    logger.info("tui_app_exited")
