"""
Validaciones CSV para Partidas de Importación Definitiva.
Paridad Clarion: VALIDA_TODA_PARIMPO_DEF, VALIDA_PARCIAL_PARIMPO_DEF, VALIDACIONES_PARIMPO_DEF.
Reutiliza la lógica de partidas_impo_temp; solo cambia el mensaje cuando la factura no existe
(«no existe en el catálogo de Importación Definitiva») y el origen de facturas (DEF/MATDE/EXDEF en tasks.py).
Estructura de columnas: misma que partidas TEM (NUMERO FACTURA, LINEA, CLASE, ... ID TYPE).
"""
from typing import Dict, Any, Optional, Set, Tuple, List

from .partidas_impo_temp import (
    _clip,
    _get,
    _check_factura_vacia,
    _check_factura_no_actualizada,
    _check_linea_si_no_autonumerar,
    _check_levantar_subpartidas_uv,
    _valida_toda_obligatorios,
    _valida_toda_numericos,
    _valida_subpartidas_duplicados,
    _valida_subpartida_tiene_principal,
    _valida_subpartida_v_no_cero,
    _validaciones_parimpo_tem,
    _warn_apostrofes_num_parte,
)


def _check_factura_existe_def(
    invoice_number: str,
    line_num: int,
    invoice_id_by_number: Dict[str, int],
    catalog_label: str = "Importación Definitiva",
) -> Optional[Dict[str, Any]]:
    """Misma lógica que _check_factura_existe; mensaje específico según catalog_label (DEF o Compras Mexicanas)."""
    if invoice_number not in invoice_id_by_number:
        return {
            "line": line_num,
            "col": "NUMERO FACTURA",
            "msg": (
                f"Error: (Celda A{line_num}) La Factura de Importación {invoice_number} "
                f"no existe en el catálogo de {catalog_label} y no se pueden hacer las validaciones. "
            ),
        }
    return None


def validate_row_partidas_impo_def(
    row: Dict[str, Any],
    line_num: int,
    autonumerar: bool,
    actualizar: bool,
    levantar_subpartidas: bool,
    calcular_costo_en_base_a_total: bool,
    validar_decimales_pza: bool,
    invoice_id_by_number: Dict[str, int],
    invoice_processed_by_number: Dict[str, bool],
    rfc_exception_updated: Set[str],
    existing_line_keys_by_invoice: Dict[str, Set[str]],
    line_counts_csv: Dict[Tuple[str, str], int],
    partidas_principales_csv: Set[Tuple[str, str]],
    partidas_principales_bd: Set[Tuple[str, str]],
    valid_class_codes: Set[str],
    class_um_by_code: Dict[str, str],
    class_fraction_by_code: Dict[str, str],
    class_desc_es_by_code: Dict[str, str],
    class_desc_en_by_code: Dict[str, str],
    valid_uom_codes: Set[str],
    valid_bulks_codes: Set[str],
    valid_country_keys: Set[str],
    valid_fraction_ame: Set[str],
    valid_payment_methods: Set[str],
    valid_valuation_methods: Set[str],
    authorized_sectors: Set[str],
    company_has_prosec: bool,
    rfc_exception_num_parte: Optional[Set[str]],
    valid_part_numbers: Optional[Set[str]],
    warnings: Optional[List[Dict[str, Any]]] = None,
    catalog_label: str = "Importación Definitiva",
) -> List[Dict[str, Any]]:
    """
    Valida una fila de CSV de Partidas de Importación Definitiva.
    Clarion: VALIDA_TODA_PARIMPO_DEF vs VALIDA_PARCIAL_PARIMPO_DEF según autonumerar, actualizar y si la partida existe.
    Reutiliza todo de partidas_impo_temp salvo el check de factura existente (mensaje DEF).
    """
    errors: List[Dict[str, Any]] = []

    err = _check_factura_vacia(row, line_num)
    if err:
        errors.append(err)
        return errors

    invoice_number = _get(row, "NUMERO FACTURA", "NUM FACTURA", "FACTURA")
    if not invoice_number:
        errors.append({"line": line_num, "col": "NUMERO FACTURA", "msg": "Requerido"})
        return errors

    for err in [
        _check_factura_existe_def(invoice_number, line_num, invoice_id_by_number, catalog_label),
        _check_factura_no_actualizada(invoice_number, line_num, invoice_processed_by_number, rfc_exception_updated),
        _check_linea_si_no_autonumerar(row, line_num, autonumerar),
        _check_levantar_subpartidas_uv(row, line_num, levantar_subpartidas),
    ]:
        if err:
            errors.append(err)

    if errors:
        return errors

    _warn_apostrofes_num_parte(row, line_num, warnings)

    linea = _get(row, "LINEA", "RENGLON", "PARTIDA")
    existing_lines = existing_line_keys_by_invoice.get(invoice_number.strip(), set())
    partida_existe = bool(linea and linea in existing_lines)
    use_partial = actualizar and not autonumerar and partida_existe

    _validaciones_kwargs = dict(
        valid_class_codes=valid_class_codes,
        class_um_by_code=class_um_by_code,
        class_fraction_by_code=class_fraction_by_code,
        class_desc_es_by_code=class_desc_es_by_code,
        class_desc_en_by_code=class_desc_en_by_code,
        valid_uom_codes=valid_uom_codes,
        valid_bulks_codes=valid_bulks_codes,
        valid_country_keys=valid_country_keys,
        valid_fraction_ame=valid_fraction_ame,
        valid_payment_methods=valid_payment_methods,
        valid_valuation_methods=valid_valuation_methods,
        authorized_sectors=authorized_sectors,
        company_has_prosec=company_has_prosec,
        validar_decimales_pza=validar_decimales_pza,
        rfc_exception_num_parte=rfc_exception_num_parte,
        invoice_number=invoice_number,
    )

    if use_partial:
        err = _validaciones_parimpo_tem(row, line_num, **_validaciones_kwargs)
        if err:
            errors.append(err)
    else:
        err = _valida_toda_obligatorios(row, line_num, levantar_subpartidas, calcular_costo_en_base_a_total)
        if err:
            errors.append(err)
        num_parte = _get(row, "NUM. PARTE", "NUMPARTE", "NUMERO PARTE", "NUM PARTE")
        if not (num_parte and str(num_parte).strip()):
            errors.append({
                "line": line_num,
                "col": "NUM. PARTE",
                "msg": f"NUM. PARTE: Requerido (obligatorio para partidas de {catalog_label}).",
            })
        err = _valida_toda_numericos(row, line_num, calcular_costo_en_base_a_total)
        if err:
            errors.append(err)
        if levantar_subpartidas:
            for err in [
                _valida_subpartidas_duplicados(invoice_number, linea, line_num, line_counts_csv),
                _valida_subpartida_tiene_principal(row, line_num, partidas_principales_csv, partidas_principales_bd),
                _valida_subpartida_v_no_cero(row, line_num),
            ]:
                if err:
                    errors.append(err)
        err = _validaciones_parimpo_tem(row, line_num, **_validaciones_kwargs)
        if err:
            errors.append(err)
        if rfc_exception_num_parte and invoice_number in rfc_exception_num_parte and valid_part_numbers is not None:
            num_parte = _get(row, "NUM. PARTE", "NUMPARTE", "NUMERO PARTE", "NUM PARTE")
            if num_parte and num_parte.upper() not in valid_part_numbers:
                errors.append({
                    "line": line_num,
                    "col": "NUM. PARTE",
                    "msg": f"Error: (Celda W{line_num}) El número de parte Capturado: {num_parte} no existe.",
                })
    return errors
