<?php
declare(strict_types=1);

require_once __DIR__ . '/functions.php';

/** Normaliza un encabezado de columna para comparacion tolerante (sin tildes, minusculas, sin espacios). */
function normalizarEncabezado(string $texto): string
{
    $texto = trim(mb_strtolower($texto));
    $texto = strtr($texto, ['á' => 'a', 'é' => 'e', 'í' => 'i', 'ó' => 'o', 'ú' => 'u', 'ñ' => 'n']);
    $texto = preg_replace('/[^a-z0-9]/', '', $texto) ?? '';
    return $texto;
}

/** Detecta el delimitador (coma o punto y coma) a partir de la primera linea del archivo. */
function detectarDelimitador(string $primeraLinea): string
{
    $comas = substr_count($primeraLinea, ',');
    $puntoComa = substr_count($primeraLinea, ';');
    return $puntoComa > $comas ? ';' : ',';
}

/**
 * Abre un CSV, detecta el delimitador y mapea sus encabezados contra los alias dados.
 * $aliases: [ 'campo_canonico' => ['alias1', 'alias2', ...] ] (los alias se normalizan internamente).
 * Retorna ['handle' => resource, 'delimitador' => string, 'indicePorCampo' => array].
 * El llamador es responsable de recorrer las filas con fgetcsv() y cerrar el handle.
 */
function abrirCsvConAlias(string $rutaArchivo, array $aliases): array
{
    $handle = fopen($rutaArchivo, 'r');
    if ($handle === false) {
        throw new RuntimeException('No fue posible abrir el archivo CSV.');
    }

    $primeraLinea = fgets($handle);
    rewind($handle);
    $delimitador = detectarDelimitador((string) $primeraLinea);

    $encabezados = fgetcsv($handle, 0, $delimitador);
    if ($encabezados === false) {
        fclose($handle);
        throw new RuntimeException('El archivo CSV está vacío o no tiene encabezados.');
    }
    // Quitar BOM UTF-8 si viene en la primera celda
    $encabezados[0] = preg_replace('/^\xEF\xBB\xBF/', '', $encabezados[0]);

    $indicePorCampo = [];
    foreach ($aliases as $campo => $listaAlias) {
        foreach ($encabezados as $idx => $enc) {
            if (in_array(normalizarEncabezado((string) $enc), array_map('normalizarEncabezado', $listaAlias), true)) {
                $indicePorCampo[$campo] = $idx;
                break;
            }
        }
    }

    return ['handle' => $handle, 'delimitador' => $delimitador, 'indicePorCampo' => $indicePorCampo];
}

/** Convierte una fila cruda de fgetcsv() en un registro asociativo usando el indice de campos. */
function mapearFilaCsv(array $fila, array $indicePorCampo): array
{
    $registro = [];
    foreach ($indicePorCampo as $campo => $idx) {
        $registro[$campo] = $fila[$idx] ?? null;
    }
    return $registro;
}

/**
 * Lee un CSV completo en memoria y retorna sus filas ya mapeadas a los alias dados.
 * Pensado para archivos pequeños/medianos (maestros de clientes, productos, etc).
 * Para archivos grandes (ventas) usar abrirCsvConAlias() + mapearFilaCsv() en streaming,
 * para no cargar todo el archivo en memoria de una vez.
 * Retorna ['filas' => array, 'faltantes' => array de campos requeridos no encontrados en el archivo].
 */
function leerCsvConAlias(string $rutaArchivo, array $aliases, array $requeridos): array
{
    $abierto = abrirCsvConAlias($rutaArchivo, $aliases);
    $handle = $abierto['handle'];
    $delimitador = $abierto['delimitador'];
    $indicePorCampo = $abierto['indicePorCampo'];

    $faltantes = array_values(array_diff($requeridos, array_keys($indicePorCampo)));

    $filas = [];
    if (empty($faltantes)) {
        while (($fila = fgetcsv($handle, 0, $delimitador)) !== false) {
            if (count($fila) === 1 && trim((string) $fila[0]) === '') {
                continue; // linea vacia
            }
            $filas[] = mapearFilaCsv($fila, $indicePorCampo);
        }
    }

    fclose($handle);
    return ['filas' => $filas, 'faltantes' => $faltantes];
}

/** Precarga codigos existentes de una tabla como set (para validar FKs sin explotar en errores). */
function precargarSet(mysqli $conn, string $tabla, string $columna): array
{
    $set = [];
    $result = $conn->query("SELECT `$columna` FROM `$tabla`");
    while ($row = $result->fetch_row()) {
        $set[$row[0]] = true;
    }
    return $set;
}

// =====================================================================
// Definicion de alias de encabezado por tipo de importacion
// =====================================================================

function aliasClientes(): array
{
    return [
        'codigo_cliente' => ['codigo_cliente', 'codigocliente', 'codigo'],
        'nit'            => ['nit'],
        'nombre'         => ['nombre'],
        'nombre_negocio' => ['nombre negocio', 'nombre_negocio', 'nombrenegocio'],
        'direccion'      => ['direccion'],
        'cod_vendedor'   => ['codvendedor', 'cod_vendedor'],
        'telefono'       => ['telefono'],
        'tipologia'      => ['tipologia'],
        'ciudad'         => ['ciudad'],
        'barrio'         => ['barrio'],
        'cod_regional'   => ['codregional', 'cod_regional'],
        'fecha_creado'   => ['fechcreado', 'fecha_creado', 'fechacreado'],
        'ruta'           => ['ruta'],
        'dias_cartera'   => ['cartera', 'dias_cartera'],
    ];
}

function aliasProductos(): array
{
    return [
        'codigo'           => ['codigo'],
        'titulo'           => ['titulo'],
        'unidad'           => ['unidad'],
        'iva'              => ['iva'],
        'categoria'        => ['categoria'],
        'subcategoria'     => ['subcategoria'],
        'nombre_comercial' => ['nombre comercial', 'nombre_comercial', 'nombrecomercial'],
        'marca'            => ['marca'],
        'factor_kg'        => ['factor a kg', 'factor_a_kg', 'factorkg'],
        'gramaje'          => ['gramaje'],
    ];
}

function aliasVendedores(): array
{
    return [
        'cod_vendedor' => ['codvendedor', 'cod_vendedor'],
        'nombre'       => ['nombre'],
        'direccion'    => ['direccion'],
        'telefono'     => ['telefono'],
        'cod_regional' => ['codregional', 'cod_regional'],
        'canal'        => ['canal'],
    ];
}

function aliasVentas(): array
{
    return [
        'factura'         => ['factura'],
        'codigo_cliente'  => ['codcliente', 'codigo_cliente', 'codigocliente'],
        'nit'             => ['nit'],
        'fecha'           => ['fecha'],
        'codigo_producto' => ['codproducto', 'codigo_producto', 'codigoproducto'],
        'cantidad'        => ['cantidad'],
        'precio'          => ['precio'],
        'valor_neto'      => ['valorneto', 'valor_neto'],
        'tarifa_iva'      => ['tarifaiva', 'tarifa_iva'],
        'valor_iva'       => ['valoriva', 'valor_iva'],
        'cod_vendedor'    => ['codvendedor', 'cod_vendedor'],
        'cod_regional'    => ['codregional', 'cod_regional'],
    ];
}

function aliasCartera(): array
{
    return [
        'factura'          => ['factura'],
        'saldo'            => ['saldo'],
        'codigo_cliente'   => ['codigo_cliente', 'codigocliente'],
        'cod_vendedor'     => ['codvendedor', 'cod_vendedor'],
        'valor_documento'  => ['valordocumento', 'valor_documento'],
        'fecha_factura'    => ['fechafactura', 'fecha_factura'],
        'dias_vencidos'    => ['diasvencidos', 'dias_vencidos'],
        'retefuente'       => ['retefuente'],
        'descuento'        => ['descuento'],
    ];
}

function aliasRecaudos(): array
{
    return [
        'fecha_recaudo'  => ['fecharecaudo', 'fecha_recaudo'],
        'codigo_cliente' => ['codigo_cliente', 'codigocliente'],
        'nombre_cliente' => ['nombrecliente', 'nombre_cliente'],
        'cod_vendedor'   => ['codvendedor', 'cod_vendedor'],
        'factura'        => ['factura'],
        'valor_recaudo'  => ['valorrecaudo', 'valor_recaudo'],
        'id_tipo_pago'   => ['idtipopgo', 'id_tipo_pago'],
        'tipo_pago'      => ['tipopago', 'tipo_pago'],
        'retefuente'     => ['retefuente'],
        'descuento'      => ['descuento'],
    ];
}

/** Config general: tipo => [aliases, requeridos]. */
function configImportacion(string $tipo): array
{
    $map = [
        'clientes'   => [aliasClientes(), ['codigo_cliente', 'nombre']],
        'productos'  => [aliasProductos(), ['codigo', 'titulo']],
        'vendedores' => [aliasVendedores(), ['cod_vendedor', 'nombre']],
        'ventas'     => [aliasVentas(), ['factura', 'codigo_producto']],
        'cartera'    => [aliasCartera(), ['factura', 'saldo']],
        'recaudos'   => [aliasRecaudos(), ['fecha_recaudo', 'factura', 'valor_recaudo']],
    ];
    if (!isset($map[$tipo])) {
        throw new InvalidArgumentException('Tipo de importación no soportado: ' . $tipo);
    }
    return $map[$tipo];
}
