"""
Configuración de plantilla CSV para Números de Parte (EstructuraCatPartesAF).
Cabeceras de descarga = Clarion: NUMERO DE PARTE, DESCRIPCION EN ESPAÑOL, etc.
"""
import csv
import io
from typing import Dict, List, Any, Optional, Tuple

from ..common.cell_value import cell_to_str
from ..common import csv_reader as common_csv_reader
from ..common.csv_hint_inject import inject_max_char_hints_into_columns
from ..common.inject_csv_labels_en import inject_en_labels_into_template_columns
from ..common.template_locale import (
    download_header_cell,
    merge_download_header_into_lookup,
    merge_labels_into_lookup,
    normalize_locale,
)
from .csv_max_chars_for_headers import PART_NUMBERS_CSV_MAX_CHARS


# Valores que indican que la primera fila es cabecera (primera columna normalizada)
FIRST_COLUMN_HEADER_VALUES = ("NUMERO DE PARTE", "NUMPARTE", "PART NUMBER")


def detect_headers_or_data(
    file_path: str,
    normalize_header_fn,
    encoding: str = "utf-8-sig",
) -> Tuple[Optional[List[str]], bool]:
    """
    Lee la primera línea del CSV y decide si es cabecera o dato.
    - Si la primera celda normalizada está en FIRST_COLUMN_HEADER_VALUES -> has_header=True, fieldnames=None.
    - Si no -> has_header=False, fieldnames=TEMPLATE_DOWNLOAD_HEADERS (primera fila = dato).
    """
    try:
        sample, _ = common_csv_reader.read_text_sample(
            file_path,
            requested_encoding=encoding,
            sample_chars=2048,
        )
    except Exception:
        try:
            sample, _ = common_csv_reader.read_text_sample(
                file_path,
                requested_encoding="auto",
                sample_chars=2048,
            )
        except Exception:
            return None, True
    lines = sample.splitlines()
    if not lines:
        return None, True
    dialect = common_csv_reader.detect_csv_dialect(sample, delimiters=",;\t")
    reader = csv.reader(io.StringIO(lines[0]), dialect=dialect)
    first_row = next(reader, None)
    if not first_row:
        return None, True
    first_cell = (first_row[0] or "").strip()
    first_cell_norm = normalize_header_fn(first_cell)
    if first_cell_norm in FIRST_COLUMN_HEADER_VALUES:
        return None, True
    return list(TEMPLATE_FIELDNAMES_FOR_READING), False


# Cabeceras que se escriben al descargar la plantilla CSV (igual que Clarion EstructuraCatPartesAF)
# Columnas I y J vacías en Clarion: dos comas entre CLAVE MONEDA y PESO UNITARIO (espacios en blanco separados por coma)
TEMPLATE_DOWNLOAD_HEADERS: List[str] = [
    "NUMERO DE PARTE",
    "DESCRIPCION EN ESPAÑOL",
    "DESCRIPCION EN INGLES",
    "CLASE",
    "UNIDAD DE MEDIDA COMERCIAL",
    "COSTO UNITARIO",
    "TIPO MONEDA COSTO",
    "CLAVE MONEDA",
    "",  # Col I vacía
    "",  # Col J vacía
    "PESO UNITARIO",
    "TIPO PESO",
    "FRACCION",
    "PAIS",
    "PREFERENCIA",
    "SECTOR",
    "RUTA DE LA IMAGEN",
]

# Misma longitud que TEMPLATE_DOWNLOAD_HEADERS; columnas I/J vacías.
TEMPLATE_DOWNLOAD_HEADERS_EN: List[str] = [
    "PART NUMBER",
    "DESCRIPTION (SPANISH)",
    "DESCRIPTION (ENGLISH)",
    "CLASS",
    "COMMERCIAL UNIT OF MEASURE",
    "UNIT COST",
    "COST CURRENCY TYPE",
    "CURRENCY CODE",
    "",
    "",
    "UNIT WEIGHT",
    "WEIGHT TYPE",
    "FRACTION",
    "COUNTRY",
    "PREFERENCE",
    "SECTOR",
    "IMAGE PATH",
]

# Para lectura cuando la primera fila es dato (sin cabecera): nombres únicos para columnas I y J
TEMPLATE_FIELDNAMES_FOR_READING: List[str] = [
    "NUMERO DE PARTE",
    "DESCRIPCION EN ESPAÑOL",
    "DESCRIPCION EN INGLES",
    "CLASE",
    "UNIDAD DE MEDIDA COMERCIAL",
    "COSTO UNITARIO",
    "TIPO MONEDA COSTO",
    "CLAVE MONEDA",
    "_COL_I_",
    "_COL_J_",
    "PESO UNITARIO",
    "TIPO PESO",
    "FRACCION",
    "PAIS",
    "PREFERENCIA",
    "SECTOR",
    "RUTA DE LA IMAGEN",
]

TEMPLATE_COLUMNS: Dict[str, List[Dict[str, Any]]] = {
    "part_numbers": [
        {"canonical": "NUMPARTE", "aliases": ["NUMERO DE PARTE", "NUMERO PARTE", "PART NUMBER", "NUM PARTE"]},
        {"canonical": "NUMPARTECOM", "aliases": ["NUMERO PARTE COMERCIAL", "COMMERCIAL PART", "PARTE COMERCIAL"]},
        {"canonical": "DESCRIPCIONE", "aliases": ["DESCRIPCION EN ESPAÑOL", "DESCRIPCION EN ESPANOL", "DESCRIPCION", "DESCRIPCION ES", "DESC ESPANOL"]},
        {"canonical": "DESCRIPCIONI", "aliases": ["DESCRIPCION EN INGLES", "DESCRIPCION EN", "DESCRIPTION", "DESC INGLES"]},
        {"canonical": "CLASE", "aliases": ["CLASS", "CLASE MATERIAL", "PART CLASS"]},
        {"canonical": "UNIMED", "aliases": ["UNIDAD DE MEDIDA COMERCIAL", "UNIDAD MEDIDA", "UNIT", "UOM", "UNIT OF MEASURE"]},
        {"canonical": "COSTOUNIT", "aliases": ["COSTO UNITARIO", "UNIT COST", "COSTO"]},
        {"canonical": "TIPOMONEDA", "aliases": ["TIPO MONEDA COSTO", "TIPO MONEDA", "MONEDA"]},
        {"canonical": "CLAVEMONEDA", "aliases": ["CLAVE MONEDA", "CURRENCY", "MONEDA CLAVE", "CURRENCY KEY"]},
        {"canonical": "PESOUNIT", "aliases": ["PESO UNITARIO", "UNIT WEIGHT", "PESO"]},
        {"canonical": "TIPOPESO", "aliases": ["TIPO PESO", "WEIGHT TYPE"]},
        {"canonical": "FRACCION", "aliases": ["FRACCION MEX"]},
        {"canonical": "FRACCIONAME", "aliases": ["FRACCION USA", "US FRACTION"]},
        {"canonical": "PAIS", "aliases": ["PAIS", "COUNTRY"]},
        {"canonical": "PREFERENCIA", "aliases": ["PREFERENCIA", "PREFERENCIA ARANCELARIA"]},
        {"canonical": "SECTOR", "aliases": ["SECTOR"]},
        {"canonical": "RUTAIMAGEN", "aliases": ["RUTA DE LA IMAGEN", "RUTA IMAGEN", "FOTO"]},
        {"canonical": "FDAKEY", "aliases": ["FDA", "FDA KEY"]},
        {"canonical": "FCCKEY", "aliases": ["FCC", "FCC KEY"]},
        {"canonical": "LICENCIA", "aliases": ["LICENSE CODE", "LICENSE"]},
        {"canonical": "ECCN", "aliases": ["ECCN CODE"]},
        {"canonical": "EXPORTCODE", "aliases": ["EXPORT CODE", "CODIGO EXPORT"]},
        {"canonical": "EXCLUSION", "aliases": ["EXCLUSION SYMBOL", "SIMBOLO EXCLUSION"]},
        {"canonical": "ACTIVO", "aliases": ["IS ACTIVE", "ACTIVE", "ACTIVO"]},
    ],
}

inject_en_labels_into_template_columns(TEMPLATE_COLUMNS)

inject_max_char_hints_into_columns(
    TEMPLATE_COLUMNS.get("part_numbers"), PART_NUMBERS_CSV_MAX_CHARS
)

_PART_ORDER_DOWNLOAD = [
    "NUMPARTE",
    "DESCRIPCIONE",
    "DESCRIPCIONI",
    "CLASE",
    "UNIMED",
    "COSTOUNIT",
    "TIPOMONEDA",
    "CLAVEMONEDA",
    None,
    None,
    "PESOUNIT",
    "TIPOPESO",
    "FRACCION",
    "PAIS",
    "PREFERENCIA",
    "SECTOR",
    "RUTAIMAGEN",
]

_PN_BY_CANON = {c["canonical"]: c for c in (TEMPLATE_COLUMNS.get("part_numbers") or [])}


def _parts_download_column_defs() -> List[Dict[str, Any]]:
    out: List[Dict[str, Any]] = []
    for key in _PART_ORDER_DOWNLOAD:
        if key is None:
            out.append({"canonical": ""})
        else:
            base = _PN_BY_CANON.get(key)
            out.append(dict(base) if base else {"canonical": key})
    return out


_PARTS_DOWNLOAD_DEFS = _parts_download_column_defs()


def download_headers_for_locale(locale: str) -> List[str]:
    loc = normalize_locale(locale)
    return [download_header_cell(d, loc) for d in _PARTS_DOWNLOAD_DEFS]


def build_normalized_lookup(normalize_header_fn) -> Dict[str, str]:
    cols = TEMPLATE_COLUMNS.get("part_numbers")
    if not cols:
        return {}
    lookup: Dict[str, str] = {}
    for item in cols:
        canonical = item["canonical"]
        lookup[normalize_header_fn(canonical)] = canonical
        for alias in item.get("aliases") or []:
            lookup[normalize_header_fn(alias)] = canonical
        merge_labels_into_lookup(item, canonical, normalize_header_fn, lookup)
        merge_download_header_into_lookup(item, canonical, normalize_header_fn, lookup)
    # Plantilla EN: mismas posiciones que TEMPLATE_DOWNLOAD_HEADERS
    for es_h, en_h in zip(TEMPLATE_DOWNLOAD_HEADERS, TEMPLATE_DOWNLOAD_HEADERS_EN):
        if not es_h or not en_h:
            continue
        es_key = normalize_header_fn(es_h)
        canon = lookup.get(es_key)
        if canon:
            lookup[normalize_header_fn(en_h)] = canon
    return lookup


def row_from_template(row: Dict[str, Any], normalize_header_fn) -> Dict[str, Any]:
    lookup = build_normalized_lookup(normalize_header_fn)
    if not lookup:
        return {normalize_header_fn(k): cell_to_str(v) for k, v in row.items()}
    out: Dict[str, Any] = {}
    for csv_header, value in row.items():
        key_norm = normalize_header_fn(csv_header)
        if key_norm in lookup:
            out[lookup[key_norm]] = cell_to_str(value)
    return out
