"""
Main application controller for the NEXUS AUTOPARTS console application.

The :class:`App` class owns the screen lifecycle loop: it renders the
current screen, reads a keypress, dispatches it, and follows any
navigation instruction the screen returns.
"""

from console.core.navigation import Navigation
from console.core.keybindings import Key


class App:
    """Top-level application controller.

    Parameters:
        renderer: A :class:`BaseRenderer` implementation (e.g. CursesRenderer).
        db:       A :class:`Database` instance for data access.
    """

    def __init__(self, renderer, db):
        self.renderer = renderer
        self.db = db
        self.nav = Navigation()
        self.screens = {}
        self.running = False
        self._register_screens()

    # ------------------------------------------------------------------
    # Screen registration
    # ------------------------------------------------------------------

    def _register_screens(self):
        """Import and register all screen instances.

        Each screen is wrapped in a try/except so that screens not yet
        implemented do not prevent the application from starting.
        """
        # --- Required screens (Task 6) --------------------------------
        try:
            from console.screens.menu_principal import MenuPrincipalScreen
            s = MenuPrincipalScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.estadisticas import EstadisticasScreen
            s = EstadisticasScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        # --- Optional screens (added by later tasks) -------------------
        try:
            from console.screens.vehiculo_nav import VehiculoNavScreen
            s = VehiculoNavScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.buscar_parte import BuscarParteScreen
            s = BuscarParteScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.buscar_texto import BuscarTextoScreen
            s = BuscarTextoScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.vin_decoder import VinDecoderScreen
            s = VinDecoderScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.catalogo import CatalogoScreen
            s = CatalogoScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.parte_detalle import ParteDetalleScreen
            s = ParteDetalleScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.comparador import ComparadorScreen
            s = ComparadorScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.admin_partes import AdminPartesScreen
            s = AdminPartesScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.admin_fabricantes import AdminFabricantesScreen
            s = AdminFabricantesScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.admin_crossref import AdminCrossrefScreen
            s = AdminCrossrefScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

        try:
            from console.screens.admin_import import AdminImportScreen
            s = AdminImportScreen()
            self.screens[s.name] = s
        except ImportError:
            pass

    # ------------------------------------------------------------------
    # Main loop
    # ------------------------------------------------------------------

    def run(self):
        """Enter the main event loop.

        Initialises the renderer, pushes the main menu onto the
        navigation stack, and loops until the user quits or the stack
        empties.
        """
        self.renderer.init_screen()
        self.running = True
        self.nav.push('menu', {}, label='Menu')

        try:
            while self.running:
                current = self.nav.current()
                if current is None:
                    break

                screen_name, context = current
                screen = self.screens.get(screen_name)

                if screen is None:
                    self.renderer.show_message(
                        f'Pantalla "{screen_name}" no disponible', 'error'
                    )
                    self.nav.pop()
                    continue

                # Render
                self.renderer.clear()
                screen.render(context, self.db, self.renderer)
                self.renderer.refresh()

                # Input
                key = self.renderer.get_key()

                # Global key: F10 = back to main menu
                if key == Key.F10:
                    self.nav.clear()
                    self.nav.push('menu', {}, label='Menu')
                    continue

                # Screen-specific key handling
                result = screen.on_key(
                    key, context, self.db, self.renderer, self.nav
                )

                if result == 'quit':
                    self.running = False
                elif result == 'back':
                    self.nav.pop()
                elif isinstance(result, tuple) and len(result) == 3:
                    name, ctx, label = result
                    self.nav.push(name, ctx, label=label)
                elif isinstance(result, str):
                    self.nav.push(result, {}, label=result)

        except KeyboardInterrupt:
            pass
        finally:
            self.renderer.cleanup()
            self.db.close()
