"""
VIN decoder screen for the NEXUS AUTOPARTS console application.

Prompts for a 17-character Vehicle Identification Number, decodes it
via the NHTSA vPIC API (with local caching), and displays the decoded
vehicle information.  The user can then navigate to the parts catalog
filtered by the matched vehicle.
"""

import json

from console.core.screens import Screen
from console.core.keybindings import Key
from console.config import APP_NAME, VERSION
from console.utils.vin_api import decode_vin_nhtsa


# Footer labels
_FOOTER_INPUT = [
    ("ENTER", "Decodificar"),
    ("ESC", "Atras"),
]

_FOOTER_RESULT = [
    ("1", "Ver partes"),
    ("2/F3", "Nuevo VIN"),
    ("ESC", "Atras"),
]

_FOOTER_ERROR = [
    ("F3", "Nuevo VIN"),
    ("ESC", "Atras"),
]


class VinDecoderScreen(Screen):
    """VIN decoder with NHTSA API integration and local cache."""

    def __init__(self):
        super().__init__(name="vin_decoder", title="Decodificador VIN")
        self._vin = None
        self._decoded = None
        self._error = None
        self._needs_input = True

    # ------------------------------------------------------------------
    # Helpers
    # ------------------------------------------------------------------

    def _decode(self, vin, db):
        """Decode a VIN using cache first, then NHTSA API."""
        self._vin = vin.upper().strip()
        self._decoded = None
        self._error = None

        # Check cache
        cached = db.get_vin_cache(self._vin)
        if cached:
            self._decoded = {
                "make": cached.get("make", ""),
                "model": cached.get("model", ""),
                "year": cached.get("year", ""),
                "engine_info": cached.get("engine_info", ""),
                "body_class": cached.get("body_class", ""),
                "drive_type": cached.get("drive_type", ""),
            }
            return

        # Call NHTSA API
        result = decode_vin_nhtsa(self._vin)

        if "error" in result:
            self._error = result["error"]
            return

        # Extract fields
        make = result.get("make", "")
        model = result.get("model", "")
        year = result.get("year", "")
        body_class = result.get("body_class", "")
        drive_type = result.get("drive_type", "")

        # Build engine info string
        engine_info_dict = result.get("engine_info", {})
        engine_parts = []
        if engine_info_dict.get("displacement_l"):
            engine_parts.append(f"{engine_info_dict['displacement_l']}L")
        if engine_info_dict.get("cylinders"):
            engine_parts.append(f"{engine_info_dict['cylinders']}cil")
        if engine_info_dict.get("fuel_type"):
            engine_parts.append(engine_info_dict["fuel_type"])
        if engine_info_dict.get("power_hp"):
            engine_parts.append(f"{engine_info_dict['power_hp']}hp")
        engine_info = " ".join(engine_parts)

        self._decoded = {
            "make": make,
            "model": model,
            "year": year,
            "engine_info": engine_info,
            "body_class": body_class,
            "drive_type": drive_type,
        }

        # Cache the result
        try:
            year_int = int(year) if year else 0
        except (ValueError, TypeError):
            year_int = 0

        try:
            db.save_vin_cache(
                vin=self._vin,
                data=json.dumps(result),
                make=make,
                model=model,
                year=year_int,
                engine_info=engine_info,
                body_class=body_class,
                drive_type=drive_type,
            )
        except Exception:
            pass  # Non-critical: caching failure should not break the flow

    def _try_match_vehicle(self, db):
        """Try to match the decoded VIN to a vehicle in the database.

        Returns a context dict for the catalogo screen if a match is
        found, or None if no match exists.
        """
        if not self._decoded:
            return None

        make = self._decoded.get("make", "")
        model = self._decoded.get("model", "")
        year = self._decoded.get("year", "")

        if not make or not model:
            return None

        try:
            year_int = int(year) if year else None
        except (ValueError, TypeError):
            year_int = None

        # Try to find matching model_year_engine records
        if year_int:
            mye_records = db.get_model_year_engine(make, model, year_int)
        else:
            mye_records = []

        ctx = {
            "level": "categories",
            "brand": make,
            "model": model,
            "year": year,
            "engine": self._decoded.get("engine_info", ""),
        }

        if mye_records:
            # Use the first match
            ctx["mye_id"] = mye_records[0]["id"]

        return ctx

    # ------------------------------------------------------------------
    # Render
    # ------------------------------------------------------------------

    def render(self, context, db, renderer):
        # Header
        renderer.draw_header(
            f" {APP_NAME} v{VERSION}",
            " DECODIFICADOR VIN ",
        )

        if self._needs_input:
            renderer.draw_footer(_FOOTER_INPUT)
            return

        if self._error:
            renderer.draw_text(5, 4, f"Error: {self._error}", "error")
            renderer.draw_footer(_FOOTER_ERROR)
            return

        if self._decoded is None:
            renderer.draw_text(5, 4, "Presione F3 para ingresar un VIN", "info")
            renderer.draw_footer(_FOOTER_ERROR)
            return

        # Display decoded VIN info
        fields = [
            ("VIN", self._vin or ""),
            ("Marca", self._decoded.get("make", "")),
            ("Modelo", self._decoded.get("model", "")),
            ("Ano", str(self._decoded.get("year", ""))),
            ("Motor", self._decoded.get("engine_info", "")),
            ("Carroceria", self._decoded.get("body_class", "")),
            ("Traccion", self._decoded.get("drive_type", "")),
        ]
        renderer.draw_detail(fields, title="INFORMACION DEL VEHICULO")

        # Action menu below detail
        h, _w = renderer.get_size()
        action_row = 5 + len(fields) + 3
        if action_row < h - 4:
            renderer.draw_text(action_row, 4, "1. Ver partes compatibles", "normal")
            renderer.draw_text(action_row + 1, 4, "2. Nueva consulta VIN", "normal")

        renderer.draw_footer(_FOOTER_RESULT)

    # ------------------------------------------------------------------
    # Key handling
    # ------------------------------------------------------------------

    def on_key(self, key, context, db, renderer, nav):
        # If we need input, show the input dialog
        if self._needs_input:
            self._needs_input = False
            value = renderer.show_input("VIN (17 caracteres)", max_len=17)
            if value is None:
                # User pressed ESC in input dialog
                if self._decoded is not None:
                    return None
                return "back"
            value = value.strip()
            if len(value) != 17:
                self._error = "El VIN debe tener exactamente 17 caracteres"
                self._decoded = None
                return None
            self._decode(value, db)
            return None

        # ESC: go back
        if key == Key.ESCAPE:
            return "back"

        # F3 or '2': new VIN input
        if key == Key.F3 or key == ord("2"):
            self._needs_input = True
            self._error = None
            return None

        # '1': view compatible parts
        if key == ord("1"):
            if self._decoded:
                cat_context = self._try_match_vehicle(db)
                if cat_context:
                    return ("catalogo", cat_context, "Catalogo")
                else:
                    renderer.show_message(
                        "No se encontro el vehiculo en la base de datos.\n"
                        "Se mostrara el catalogo completo.",
                        "info",
                    )
                    return ("catalogo", {"level": "categories"}, "Catalogo")
            return None

        return None
