"""
Vehicle drill-down navigation screen for the NEXUS AUTOPARTS console application.

Guides the user through a four-level hierarchy:

    Brand -> Model -> Year -> Engine

Each level presents a filterable list.  After engine selection the screen
navigates to the catalogue (``catalogo``) with the resolved
``model_year_engine`` id.
"""

from console.core.screens import Screen
from console.core.keybindings import Key

# Ordered sequence of drill-down levels.
_LEVELS = ("brand", "model", "year", "engine")

# Human-readable titles for each level (Spanish).
_LEVEL_TITLES = {
    "brand":  "Seleccione Marca",
    "model":  "Seleccione Modelo",
    "year":   "Seleccione Ano",
    "engine": "Seleccione Motor",
}


class VehiculoNavScreen(Screen):
    """Four-level vehicle drill-down: Brand -> Model -> Year -> Engine."""

    def __init__(self):
        super().__init__("vehiculo_nav", "Consulta por Vehiculo")

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    def _get_title_for_level(self, context):
        """Return the title string for the current drill-down level."""
        level = context.get("level", "brand")
        return _LEVEL_TITLES.get(level, "Seleccione")

    def _get_subtitle(self, context):
        """Build a breadcrumb subtitle from selections made so far.

        Example: ``"TOYOTA > CAMRY > 2023 > Seleccione motor"``
        """
        parts = []
        if context.get("brand"):
            parts.append(context["brand"])
        if context.get("model"):
            parts.append(context["model"])
        if context.get("year") is not None:
            parts.append(str(context["year"]))

        level = context.get("level", "brand")
        parts.append(_LEVEL_TITLES.get(level, ""))
        return " > ".join(parts)

    def _load_items(self, context, db):
        """Fetch the item list from the database for the current level."""
        level = context.get("level", "brand")

        if level == "brand":
            context["all_items"] = db.get_brands()
        elif level == "model":
            context["all_items"] = db.get_models(brand=context.get("brand"))
        elif level == "year":
            context["all_items"] = db.get_years(
                brand=context.get("brand"),
                model=context.get("model"),
            )
        elif level == "engine":
            context["all_items"] = db.get_engines(
                brand=context.get("brand"),
                model=context.get("model"),
                year=context.get("year"),
            )
        else:
            context["all_items"] = []

        self._apply_filter(context)

    def _apply_filter(self, context):
        """Reduce ``all_items`` to those matching ``filter_text``.

        Matching is a case-insensitive substring test on the display name.
        """
        level = context.get("level", "brand")
        ft = context.get("filter_text", "").lower()
        all_items = context.get("all_items", [])

        if ft:
            context["filtered_items"] = [
                item for item in all_items
                if ft in self._get_display_name(item, level).lower()
            ]
        else:
            context["filtered_items"] = list(all_items)

    @staticmethod
    def _get_display_name(item, level):
        """Extract the human-readable display string from an item dict."""
        if level == "year":
            return str(item.get("year", ""))
        return item.get("name", "")

    # ------------------------------------------------------------------
    # Screen interface
    # ------------------------------------------------------------------

    def render(self, context, db, renderer):
        # First-render initialisation
        if "level" not in context:
            context["level"] = "brand"
            context["filter_text"] = ""
            context["selected_index"] = 0
            self._load_items(context, db)

        level = context["level"]
        title = self._get_title_for_level(context)
        subtitle = self._get_subtitle(context)
        renderer.draw_header(title, subtitle)

        # Build the (number, label) tuples expected by draw_filter_list.
        filtered = context.get("filtered_items", [])
        display_items = [
            (str(idx + 1), self._get_display_name(item, level))
            for idx, item in enumerate(filtered)
        ]

        renderer.draw_filter_list(
            display_items,
            context.get("filter_text", ""),
            context.get("selected_index", 0),
            title=f"SELECCIONAR {level.upper()}",
        )

        renderer.draw_footer([
            ("Escriba", "Filtrar"),
            ("ENTER", "Seleccionar"),
            ("\u2191\u2193", "Mover"),
            ("ESC", "Atras"),
        ])

    def on_key(self, key, context, db, renderer, nav):
        filtered = context.get("filtered_items", [])
        level = context.get("level", "brand")

        # -- ESC: go back one level, or return to menu ----------------
        if key == Key.ESCAPE:
            if level == "brand":
                return "back"
            prev = _LEVELS[_LEVELS.index(level) - 1]
            context["level"] = prev
            context["filter_text"] = ""
            context["selected_index"] = 0
            self._load_items(context, db)
            return None

        # -- ENTER: select item and advance ---------------------------
        if key == Key.ENTER and filtered:
            idx = context.get("selected_index", 0)
            if idx >= len(filtered):
                return None
            selected = filtered[idx]

            if level == "brand":
                context["brand"] = selected["name"]
                context["level"] = "model"
            elif level == "model":
                context["model"] = selected["name"]
                context["level"] = "year"
            elif level == "year":
                context["year"] = selected["year"]
                context["level"] = "engine"
            elif level == "engine":
                context["engine_id"] = selected["id"]
                context["engine_name"] = selected["name"]
                # Resolve the model_year_engine row
                mye_list = db.get_model_year_engine(
                    context["brand"],
                    context["model"],
                    context["year"],
                    context["engine_id"],
                )
                if mye_list:
                    mye_id = mye_list[0]["id"]
                    return (
                        "catalogo",
                        {
                            "mye_id": mye_id,
                            "brand": context["brand"],
                            "model": context["model"],
                            "year": context["year"],
                            "engine": context["engine_name"],
                        },
                        f"{context['brand']} {context['model']} {context['year']}",
                    )
                else:
                    renderer.show_message(
                        "No se encontro configuracion para este vehiculo",
                        "error",
                    )
                    return None

            # Reset filter for the new level
            context["filter_text"] = ""
            context["selected_index"] = 0
            self._load_items(context, db)
            return None

        # -- Arrow keys: move selection cursor ------------------------
        if key == Key.UP:
            if context.get("selected_index", 0) > 0:
                context["selected_index"] -= 1
            return None

        if key == Key.DOWN:
            if context.get("selected_index", 0) < len(filtered) - 1:
                context["selected_index"] += 1
            return None

        # -- Backspace: trim filter text ------------------------------
        if key in (Key.BACKSPACE, 8, 263):
            if context.get("filter_text"):
                context["filter_text"] = context["filter_text"][:-1]
                self._apply_filter(context)
                context["selected_index"] = 0
            return None

        # -- Printable characters: append to filter -------------------
        if isinstance(key, int) and 32 <= key <= 126:
            context["filter_text"] = context.get("filter_text", "") + chr(key)
            self._apply_filter(context)
            context["selected_index"] = 0
            return None

        return None
