"""
Admin CRUD screen for Parts in the NEXUS AUTOPARTS console application.

Provides a paginated list view with create (F3), edit (ENTER), and
delete (F8/Del) operations.  Form editing is handled inline with
field-by-field navigation.
"""

from console.core.screens import Screen
from console.core.keybindings import Key
from console.config import APP_NAME, VERSION
from console.utils.formatting import truncate, pad_right


# Form field definitions for create/edit
_FIELDS = [
    {'label': 'Numero OEM', 'key': 'oem_part_number', 'width': 20},
    {'label': 'Nombre', 'key': 'name', 'width': 40},
    {'label': 'Nombre (ES)', 'key': 'name_es', 'width': 40},
    {'label': 'Grupo ID', 'key': 'group_id', 'width': 5, 'hint': 'F1=Lista'},
    {'label': 'Descripcion', 'key': 'description', 'width': 50},
    {'label': 'Descripcion ES', 'key': 'description_es', 'width': 50},
    {'label': 'Material', 'key': 'material', 'width': 20},
    {'label': 'Peso (kg)', 'key': 'weight_kg', 'width': 8},
    {'label': 'Descontinuada', 'key': 'is_discontinued', 'width': 1, 'hint': 'S/N'},
]

# Footer labels per mode
_FOOTER_LIST = [
    ("F3", "Nuevo"),
    ("ENTER", "Editar"),
    ("F8", "Eliminar"),
    ("PgUp/Dn", "Paginar"),
    ("ESC", "Atras"),
]

_FOOTER_FORM = [
    ("TAB/Down", "Siguiente"),
    ("Up", "Anterior"),
    ("F9", "Guardar"),
    ("ESC", "Cancelar"),
]


class AdminPartesScreen(Screen):
    """Admin CRUD screen for the parts table."""

    def __init__(self):
        super().__init__(name="admin_partes", title="Administracion de Partes")
        self._mode = 'list'          # 'list' or 'form'
        self._page = 1
        self._per_page = 15
        self._selected = 0
        self._parts = []
        self._editing_id = None      # None = creating, int = editing
        self._focused_field = 0
        self._form_data = {}
        self._dirty = False

    # ------------------------------------------------------------------
    # Data loading
    # ------------------------------------------------------------------

    def _load_parts(self, db):
        """Load the current page of parts."""
        self._parts = db.get_parts(page=self._page, per_page=self._per_page)

    def _init_form(self, part=None):
        """Initialise form_data from an existing part or blank."""
        self._form_data = {}
        if part:
            for f in _FIELDS:
                key = f['key']
                val = part.get(key, '')
                if key == 'is_discontinued':
                    val = 'S' if val else 'N'
                self._form_data[key] = str(val) if val is not None else ''
        else:
            for f in _FIELDS:
                self._form_data[f['key']] = ''
        self._focused_field = 0
        self._dirty = False

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

    def render(self, context, db, renderer):
        renderer.draw_header(
            f" {APP_NAME} v{VERSION}",
            " ADMINISTRACION DE PARTES ",
        )

        if self._mode == 'list':
            self._render_list(db, renderer)
        else:
            self._render_form(renderer)

    def _render_list(self, db, renderer):
        """Render the paginated parts list."""
        self._load_parts(db)

        headers = ["NUMERO OEM", "NOMBRE", "GRUPO", "MATERIAL", "DISCONT"]
        widths = [18, 25, 15, 12, 7]
        rows = []
        for p in self._parts:
            disc = "Si" if p.get("is_discontinued") else ""
            rows.append((
                truncate(p.get("oem_part_number", ""), 18),
                truncate(p.get("name_es") or p.get("name", ""), 25),
                truncate(p.get("group_name", ""), 15),
                truncate(p.get("material", "") or "", 12),
                disc,
            ))

        renderer.draw_table(
            headers,
            rows,
            widths,
            page_info={
                "page": self._page,
                "total_pages": self._page,
                "total_rows": len(rows),
            },
            selected_row=self._selected,
        )
        renderer.draw_footer(_FOOTER_LIST)

    def _render_form(self, renderer):
        """Render the create/edit form."""
        title = "EDITAR PARTE" if self._editing_id else "NUEVA PARTE"
        fields = []
        for f in _FIELDS:
            fields.append({
                'label': f['label'],
                'value': self._form_data.get(f['key'], ''),
                'width': f['width'],
                'hint': f.get('hint', ''),
            })
        renderer.draw_form(fields, focused_index=self._focused_field, title=title)
        renderer.draw_footer(_FOOTER_FORM)

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

    def on_key(self, key, context, db, renderer, nav):
        if self._mode == 'list':
            return self._handle_list_key(key, context, db, renderer)
        else:
            return self._handle_form_key(key, db, renderer)

    def _handle_list_key(self, key, context, db, renderer):
        """Handle keys in list mode."""
        # ESC: go back
        if key == Key.ESCAPE:
            return "back"

        # Arrow navigation
        if key == Key.UP:
            if self._selected > 0:
                self._selected -= 1
            return None

        if key == Key.DOWN:
            if self._parts and self._selected < len(self._parts) - 1:
                self._selected += 1
            return None

        # PgDn: next page
        if key == Key.PGDN:
            if len(self._parts) == self._per_page:
                self._page += 1
                self._selected = 0
            return None

        # PgUp: previous page
        if key == Key.PGUP:
            if self._page > 1:
                self._page -= 1
                self._selected = 0
            return None

        # F3: create new part
        if key == Key.F3:
            self._mode = 'form'
            self._editing_id = None
            self._init_form()
            return None

        # ENTER: edit selected part
        if key == Key.ENTER:
            if self._parts and 0 <= self._selected < len(self._parts):
                part_row = self._parts[self._selected]
                part = db.get_part(part_row["id"])
                if part:
                    self._editing_id = part["id"]
                    self._mode = 'form'
                    self._init_form(part)
            return None

        # Number keys 1-9: edit part at that row index
        if 49 <= key <= 57:
            idx = key - 49
            if 0 <= idx < len(self._parts):
                part_row = self._parts[idx]
                part = db.get_part(part_row["id"])
                if part:
                    self._editing_id = part["id"]
                    self._mode = 'form'
                    self._init_form(part)
            return None

        # F8 or DEL: delete selected part
        if key in (Key.F8, 330):  # 330 = KEY_DC (Delete)
            if self._parts and 0 <= self._selected < len(self._parts):
                part = self._parts[self._selected]
                name = part.get("name_es") or part.get("name", "")
                oem = part.get("oem_part_number", "")
                confirmed = renderer.show_message(
                    f"Eliminar parte?\n{oem} - {name}",
                    "confirm",
                )
                if confirmed:
                    db.delete_part(part["id"])
                    # Adjust selection
                    if self._selected >= len(self._parts) - 1:
                        self._selected = max(0, self._selected - 1)
            return None

        return None

    def _handle_form_key(self, key, db, renderer):
        """Handle keys in form mode."""
        # ESC: cancel form (with dirty check)
        if key == Key.ESCAPE:
            if self._dirty:
                confirmed = renderer.show_message(
                    "Descartar cambios?", "confirm"
                )
                if not confirmed:
                    return None
            self._mode = 'list'
            return None

        # TAB / Down: next field
        if key in (Key.TAB, Key.DOWN):
            if self._focused_field < len(_FIELDS) - 1:
                self._focused_field += 1
            return None

        # Up: previous field
        if key == Key.UP:
            if self._focused_field > 0:
                self._focused_field -= 1
            return None

        # F9: save
        if key == Key.F9:
            return self._save(db, renderer)

        # Backspace: delete last char from current field value
        if key in (Key.BACKSPACE, 8):
            field_key = _FIELDS[self._focused_field]['key']
            val = self._form_data.get(field_key, '')
            if val:
                self._form_data[field_key] = val[:-1]
                self._dirty = True
            return None

        # Printable characters: append to current field
        if 32 <= key <= 126:
            field_def = _FIELDS[self._focused_field]
            field_key = field_def['key']
            val = self._form_data.get(field_key, '')
            if len(val) < field_def['width']:
                self._form_data[field_key] = val + chr(key)
                self._dirty = True
            return None

        return None

    def _save(self, db, renderer):
        """Validate and save the form data."""
        data = dict(self._form_data)

        # Validate required fields
        if not data.get('oem_part_number', '').strip():
            renderer.show_message("Numero OEM es requerido", "error")
            return None
        if not data.get('name', '').strip():
            renderer.show_message("Nombre es requerido", "error")
            return None

        # Convert types
        gid = data.get('group_id', '').strip()
        data['group_id'] = int(gid) if gid.isdigit() else None

        wkg = data.get('weight_kg', '').strip()
        try:
            data['weight_kg'] = float(wkg) if wkg else None
        except ValueError:
            data['weight_kg'] = None

        disc = data.get('is_discontinued', '').strip().upper()
        data['is_discontinued'] = 1 if disc == 'S' else 0

        try:
            if self._editing_id:
                db.update_part(self._editing_id, data)
                renderer.show_message("Parte actualizada correctamente", "info")
            else:
                db.create_part(data)
                renderer.show_message("Parte creada correctamente", "info")
        except Exception as exc:
            renderer.show_message(f"Error al guardar:\n{exc}", "error")
            return None

        self._mode = 'list'
        self._dirty = False
        return None
