<?php
// Verificar BASEPATH por seguridad
if (!defined('BASEPATH')) {
    die(json_encode(['success' => false, 'message' => 'Acceso directo no permitido']));
}

/**
 * Clase para manejar la migración de productos desde bases de datos externas
 * Versión 2.0 - Migración completa con precios, áreas, almacenes e impresoras
 */
class Migracion
{
    private $conn;
    private $externalConn = null;

    // Categorías a ignorar para selección principal
    private $categoriasIgnorar = ['DEL SISTEMA', 'KERIGMA'];

    public function __construct($conn)
    {
        $this->conn = $conn;
    }

    /**
     * Probar conexión a base de datos externa
     */
    public function probarConexion($data)
    {
        try {
            $host = $data['host'] ?? 'localhost';
            $usuario = $data['usuario'] ?? '';
            $password = $data['password'] ?? '';
            $base_datos = $data['base_datos'] ?? '';

            if (empty($usuario) || empty($base_datos)) {
                return ['success' => false, 'message' => 'Usuario y base de datos son requeridos'];
            }

            // Intentar conectar
            $externalConn = new mysqli($host, $usuario, $password, $base_datos);

            if ($externalConn->connect_error) {
                return ['success' => false, 'message' => 'Error de conexión: ' . $externalConn->connect_error];
            }

            $externalConn->set_charset("utf8mb4");

            // Obtener lista de tablas
            $tablas = [];
            $result = $externalConn->query("SHOW TABLE STATUS");

            if ($result) {
                while ($row = $result->fetch_assoc()) {
                    $tablas[] = [
                        'name' => $row['Name'],
                        'rows' => (int)$row['Rows'],
                        'engine' => $row['Engine']
                    ];
                }
            }

            $externalConn->close();

            return [
                'success' => true,
                'message' => 'Conexión exitosa',
                'data' => [
                    'tablas' => $tablas
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Obtener columnas de una tabla
     */
    public function obtenerColumnas($data)
    {
        try {
            $host = $data['host'] ?? 'localhost';
            $usuario = $data['usuario'] ?? '';
            $password = $data['password'] ?? '';
            $base_datos = $data['base_datos'] ?? '';
            $tabla = $data['tabla'] ?? '';

            if (empty($tabla)) {
                return ['success' => false, 'message' => 'Nombre de tabla requerido'];
            }

            $externalConn = new mysqli($host, $usuario, $password, $base_datos);

            if ($externalConn->connect_error) {
                return ['success' => false, 'message' => 'Error de conexión: ' . $externalConn->connect_error];
            }

            $externalConn->set_charset("utf8mb4");

            // Obtener columnas
            $columnas = [];
            $result = $externalConn->query("DESCRIBE `" . $externalConn->real_escape_string($tabla) . "`");

            if ($result) {
                while ($row = $result->fetch_assoc()) {
                    $columnas[] = [
                        'name' => $row['Field'],
                        'type' => $row['Type'],
                        'null' => $row['Null'],
                        'key' => $row['Key'],
                        'default' => $row['Default']
                    ];
                }
            }

            // Obtener algunos registros de ejemplo
            $ejemplo = [];
            $resultEjemplo = $externalConn->query("SELECT * FROM `" . $externalConn->real_escape_string($tabla) . "` LIMIT 3");
            if ($resultEjemplo) {
                while ($row = $resultEjemplo->fetch_assoc()) {
                    $ejemplo[] = $row;
                }
            }

            $externalConn->close();

            return [
                'success' => true,
                'data' => [
                    'columnas' => $columnas,
                    'ejemplo' => $ejemplo
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Vista previa de la migración
     */
    public function previewMigracion($data)
    {
        try {
            $host = $data['host'] ?? 'localhost';
            $usuario = $data['usuario'] ?? '';
            $password = $data['password'] ?? '';
            $base_datos = $data['base_datos'] ?? '';
            $tabla = $data['tabla'] ?? '';
            $mapeo = $data['mapeo'] ?? [];
            $limite = $data['limite'] ?? 10;

            if (empty($tabla) || empty($mapeo)) {
                return ['success' => false, 'message' => 'Tabla y mapeo son requeridos'];
            }

            $externalConn = new mysqli($host, $usuario, $password, $base_datos);

            if ($externalConn->connect_error) {
                return ['success' => false, 'message' => 'Error de conexión'];
            }

            $externalConn->set_charset("utf8mb4");

            // Construir query con campos mapeados
            $selectFields = [];
            foreach ($mapeo as $campoDestino => $columnaOrigen) {
                if (!empty($columnaOrigen)) {
                    $selectFields[] = "`" . $externalConn->real_escape_string($columnaOrigen) . "` AS `" . $campoDestino . "`";
                }
            }

            if (empty($selectFields)) {
                return ['success' => false, 'message' => 'No hay campos mapeados'];
            }

            $query = "SELECT " . implode(", ", $selectFields) . " FROM `" . $externalConn->real_escape_string($tabla) . "` LIMIT " . (int)$limite;

            $result = $externalConn->query($query);
            $preview = [];

            if ($result) {
                while ($row = $result->fetch_assoc()) {
                    $preview[] = $row;
                }
            }

            // Contar total de registros
            $countResult = $externalConn->query("SELECT COUNT(*) as total FROM `" . $externalConn->real_escape_string($tabla) . "`");
            $total = 0;
            if ($countResult) {
                $countRow = $countResult->fetch_assoc();
                $total = (int)$countRow['total'];
            }

            $externalConn->close();

            return [
                'success' => true,
                'data' => [
                    'preview' => $preview,
                    'total' => $total
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Migrar áreas de Kerigma como almacenes en pos_abarrotes
     */
    private function migrarAreasComoAlmacenes($externalConn)
    {
        $almacenesCreados = 0;
        $almacenesMap = []; // codigo_unico => almacen_id

        // Verificar si existe la tabla catalogo_areas
        $checkTable = $externalConn->query("SHOW TABLES LIKE 'catalogo_areas'");
        if ($checkTable->num_rows === 0) {
            return $almacenesMap;
        }

        // Obtener áreas activas de Kerigma
        $query = "SELECT id, codigo_unico, nombre_area, descripcion FROM catalogo_areas WHERE activa = 1";
        $result = $externalConn->query($query);

        if (!$result) {
            return $almacenesMap;
        }

        // Preparar statements
        $stmtCheck = $this->conn->prepare("SELECT id FROM almacenes WHERE codigo = ? OR nombre = ? LIMIT 1");
        $stmtInsert = $this->conn->prepare("INSERT INTO almacenes (nombre, codigo, activo) VALUES (?, ?, 1)");

        while ($row = $result->fetch_assoc()) {
            $codigo = $row['codigo_unico'];
            $nombre = $row['nombre_area'];

            // Verificar si ya existe
            $stmtCheck->bind_param("ss", $codigo, $nombre);
            $stmtCheck->execute();
            $checkResult = $stmtCheck->get_result();

            if ($existente = $checkResult->fetch_assoc()) {
                $almacenesMap[$row['id']] = $existente['id'];
            } else {
                // Crear nuevo almacén
                $stmtInsert->bind_param("ss", $nombre, $codigo);
                if ($stmtInsert->execute()) {
                    $almacenesMap[$row['id']] = $this->conn->insert_id;
                    $almacenesCreados++;
                }
            }
        }

        $stmtCheck->close();
        $stmtInsert->close();

        return $almacenesMap;
    }

    /**
     * Obtener mapeo de productos a áreas e impresoras
     */
    private function obtenerMapeoProductosAreas($externalConn)
    {
        $mapeo = []; // codigo_producto => ['area_id' => X, 'impresora' => 'nombre']

        // Verificar si existen las tablas
        $checkTable = $externalConn->query("SHOW TABLES LIKE 'productos_areas'");
        if ($checkTable->num_rows === 0) {
            return $mapeo;
        }

        $query = "
            SELECT
                pa.codigo_producto,
                pa.area_id,
                ia.nombre_impresora
            FROM productos_areas pa
            LEFT JOIN impresoras_areas ia ON pa.area_id = ia.area_id AND ia.es_principal = 1 AND ia.activa = 1
            WHERE pa.activo = 1
        ";

        $result = $externalConn->query($query);

        if ($result) {
            while ($row = $result->fetch_assoc()) {
                $mapeo[$row['codigo_producto']] = [
                    'area_id' => $row['area_id'],
                    'impresora' => $row['nombre_impresora']
                ];
            }
        }

        return $mapeo;
    }

    /**
     * Obtener precios de tblprecios para un producto y unidad
     */
    private function obtenerPreciosLista($externalConn, $codigo, $unidad, $equivalencia)
    {
        $precios = [
            'precio_lista' => 0,
            'precio1' => 0,
            'precio2' => 0,
            'precio3' => 0,
            'precio4' => 0,
            'precio5' => 0,
            'precio6' => 0
        ];

        $query = "
            SELECT COD_LISTA, PRE_IVA, PRE_ART
            FROM tblprecios
            WHERE COD1_ART = ? AND COD_UND = ? AND EQV_UND = ?
            ORDER BY COD_LISTA
        ";

        $stmt = $externalConn->prepare($query);
        $stmt->bind_param("ssd", $codigo, $unidad, $equivalencia);
        $stmt->execute();
        $result = $stmt->get_result();

        while ($row = $result->fetch_assoc()) {
            $lista = (int)$row['COD_LISTA'];
            $precioIva = floatval($row['PRE_IVA']);

            switch ($lista) {
                case 1: // PRECIO DE LISTA
                    $precios['precio_lista'] = $precioIva;
                    break;
                case 2: // VTA1
                    $precios['precio1'] = $precioIva;
                    break;
                case 3: // VTA2
                    $precios['precio2'] = $precioIva;
                    break;
                case 4: // VTA3
                    $precios['precio3'] = $precioIva;
                    break;
                case 5: // VTA4
                    $precios['precio4'] = $precioIva;
                    break;
                case 6: // VTA5
                    $precios['precio5'] = $precioIva;
                    break;
                case 7: // VTA6
                    $precios['precio6'] = $precioIva;
                    break;
            }
        }

        $stmt->close();
        return $precios;
    }

    /**
     * Obtener la mejor categoría para un producto (ignorando DEL SISTEMA y KERIGMA)
     */
    private function obtenerMejorCategoria($externalConn, $codigo)
    {
        $query = "
            SELECT c.DES_AGR as categoria
            FROM tblgpoarticulos g
            INNER JOIN tblcatagrupacionart c ON g.COD_AGR = c.COD_AGR
            WHERE g.COD1_ART = ?
            ORDER BY
                CASE
                    WHEN c.DES_AGR IN ('DEL SISTEMA', 'KERIGMA') THEN 1
                    ELSE 0
                END,
                g.COD_AGR
            LIMIT 1
        ";

        $stmt = $externalConn->prepare($query);
        $stmt->bind_param("s", $codigo);
        $stmt->execute();
        $result = $stmt->get_result();

        $categoria = null;
        if ($row = $result->fetch_assoc()) {
            $cat = $row['categoria'];
            // Solo usar si no está en la lista de ignorar
            if (!in_array(strtoupper($cat), array_map('strtoupper', $this->categoriasIgnorar))) {
                $categoria = $cat;
            }
        }

        $stmt->close();

        // Si no encontró categoría válida, buscar la primera que no sea DEL SISTEMA o KERIGMA
        if (!$categoria) {
            $query2 = "
                SELECT c.DES_AGR as categoria
                FROM tblgpoarticulos g
                INNER JOIN tblcatagrupacionart c ON g.COD_AGR = c.COD_AGR
                WHERE g.COD1_ART = ?
                AND c.DES_AGR NOT IN ('DEL SISTEMA', 'KERIGMA')
                LIMIT 1
            ";
            $stmt2 = $externalConn->prepare($query2);
            $stmt2->bind_param("s", $codigo);
            $stmt2->execute();
            $result2 = $stmt2->get_result();
            if ($row2 = $result2->fetch_assoc()) {
                $categoria = $row2['categoria'];
            }
            $stmt2->close();
        }

        return $categoria;
    }

    /**
     * Migrar descuentos por volumen de Kerigma
     * Calcula el porcentaje de descuento comparando precio volumen vs precio normal
     */
    private function migrarDescuentosVolumen($externalConn)
    {
        $migrados = 0;

        // Verificar si existe la tabla tblprecvolum
        $checkTable = $externalConn->query("SHOW TABLES LIKE 'tblprecvolum'");
        if ($checkTable->num_rows === 0) {
            return $migrados;
        }

        // Query para obtener descuentos con precio normal para calcular porcentaje
        $query = "
            SELECT
                pv.COD1_ART as codigo,
                pv.COD_UND as unidad,
                pv.CAN_VOL as cantidad_minima,
                pv.PRE_IVA as precio_volumen,
                u.PRE_IVA as precio_normal
            FROM tblprecvolum pv
            INNER JOIN tblundcospreart u ON pv.COD1_ART = u.COD1_ART AND pv.COD_UND = u.COD_UND
            WHERE pv.CAN_VOL > 0 AND pv.PRE_IVA > 0 AND u.PRE_IVA > 0
        ";

        $result = $externalConn->query($query);

        if (!$result) {
            return $migrados;
        }

        // Preparar statements
        $stmtProducto = $this->conn->prepare("SELECT id FROM productos WHERE codigo_corto = ? LIMIT 1");
        $stmtCheck = $this->conn->prepare("SELECT id FROM descuentos_volumen WHERE producto_id = ? AND cantidad_minima = ? LIMIT 1");
        $stmtInsert = $this->conn->prepare("
            INSERT INTO descuentos_volumen (producto_id, cantidad_minima, descuento_porcentaje, activo)
            VALUES (?, ?, ?, 1)
        ");

        while ($row = $result->fetch_assoc()) {
            $codigo = $row['codigo'];
            $unidad = strtoupper(trim($row['unidad']));
            $codigoProducto = $codigo . '_' . $unidad;

            // Buscar producto en pos_abarrotes
            $stmtProducto->bind_param("s", $codigoProducto);
            $stmtProducto->execute();
            $prodResult = $stmtProducto->get_result();

            if ($prodRow = $prodResult->fetch_assoc()) {
                $productoId = $prodRow['id'];
                $cantidadMinima = floatval($row['cantidad_minima']);
                $precioNormal = floatval($row['precio_normal']);
                $precioVolumen = floatval($row['precio_volumen']);

                // Calcular porcentaje de descuento
                // descuento = ((precio_normal - precio_volumen) / precio_normal) * 100
                if ($precioNormal > 0 && $precioVolumen < $precioNormal) {
                    $descuentoPorcentaje = round((($precioNormal - $precioVolumen) / $precioNormal) * 100, 2);

                    // Verificar si ya existe
                    $stmtCheck->bind_param("id", $productoId, $cantidadMinima);
                    $stmtCheck->execute();
                    if (!$stmtCheck->get_result()->fetch_assoc()) {
                        // Insertar descuento
                        $stmtInsert->bind_param("idd", $productoId, $cantidadMinima, $descuentoPorcentaje);
                        if ($stmtInsert->execute()) {
                            $migrados++;
                        }
                    }
                }
            }
        }

        $stmtProducto->close();
        $stmtCheck->close();
        $stmtInsert->close();

        return $migrados;
    }

    /**
     * Migración especial para sistema Kerigma con equivalencias - VERSIÓN COMPLETA
     */
    public function ejecutarMigracionKerigma($data)
    {
        try {
            $host = $data['host'] ?? 'localhost';
            $usuario = $data['usuario'] ?? '';
            $password = $data['password'] ?? '';
            $base_datos = $data['base_datos'] ?? '';

            $externalConn = new mysqli($host, $usuario, $password, $base_datos);

            if ($externalConn->connect_error) {
                return ['success' => false, 'message' => 'Error de conexión externa'];
            }

            $externalConn->set_charset("utf8mb4");

            // 1. Migrar áreas como almacenes
            $almacenesMap = $this->migrarAreasComoAlmacenes($externalConn);

            // 2. Obtener mapeo de productos a áreas e impresoras
            $productosAreasMap = $this->obtenerMapeoProductosAreas($externalConn);

            // 3. Query para obtener TODAS las unidades de cada producto
            $query = "
                SELECT
                    a.COD1_ART as codigo,
                    a.DES1_ART as nombre,
                    a.DES2_ART as descripcion,
                    a.EXI_ACT as stock,
                    a.CVE_CFDI as cve_cfdi,
                    u.COD_UND as unidad,
                    u.EQV_UND as equivalencia,
                    u.PRE_UND as precio_sin_iva,
                    u.PRE_IVA as precio_con_iva,
                    u.COS_UCO as costo,
                    COALESCE(e.CODART_EXTRA, u.COD_BARRAS) as codigo_barras
                FROM tblcatarticulos a
                INNER JOIN tblundcospreart u ON a.COD1_ART = u.COD1_ART
                LEFT JOIN tblcodarticuloextra e ON a.COD1_ART = e.COD_ART
                WHERE a.DES1_ART IS NOT NULL AND a.DES1_ART != ''
                ORDER BY a.COD1_ART, u.EQV_UND ASC
            ";

            $result = $externalConn->query($query);

            if (!$result) {
                return ['success' => false, 'message' => 'Error al leer datos: ' . $externalConn->error];
            }

            // Agrupar productos por código
            $productosAgrupados = [];
            while ($row = $result->fetch_assoc()) {
                $codigo = $row['codigo'];
                if (!isset($productosAgrupados[$codigo])) {
                    $productosAgrupados[$codigo] = [];
                }
                $productosAgrupados[$codigo][] = $row;
            }

            $migrados = 0;
            $equivalenciasCreadas = 0;
            $errores = [];
            $omitidos = 0;
            $almacenesMigrados = count($almacenesMap);
            $categoriasCreadas = 0;

            // Cache de categorías
            $categoriasCache = [];

            // Preparar statements
            $stmtCheck = $this->conn->prepare("SELECT id FROM productos WHERE codigo_corto = ? LIMIT 1");

            $stmtInsert = $this->conn->prepare("
                INSERT INTO productos (
                    nombre, descripcion, codigo_corto, codigo_barras, cve_cfdi,
                    precio_compra, precio_lista, precio1, precio2, precio3, precio4, precio5, precio6,
                    stock, stock_minimo, unidad_medida, categoria_id, almacen_id, impresora, es_base, activo
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)
            ");

            $stmtEquivalencia = $this->conn->prepare("
                INSERT INTO producto_equivalencias (producto_id, producto_equivalente_id, cantidad, activo)
                VALUES (?, ?, ?, 1)
            ");

            // Mapeo de unidades
            $unidadMap = [
                'pza' => 'pz',
                'kg' => 'kg',
                'lt' => 'lt',
                'cja' => 'caja',
                'pqt' => 'paquete',
                'blt' => 'bulto',
                'bot' => 'botella',
                'gal' => 'galon',
                'lta' => 'lata'
            ];

            foreach ($productosAgrupados as $codigo => $unidades) {
                try {
                    // Ordenar por equivalencia (1 primero = unidad base)
                    usort($unidades, function ($a, $b) {
                        return floatval($a['equivalencia']) - floatval($b['equivalencia']);
                    });

                    $productoBaseId = null;
                    $nombreBase = trim($unidades[0]['nombre'] ?? '');

                    if (empty($nombreBase)) {
                        continue;
                    }

                    // Obtener la mejor categoría (ignorando DEL SISTEMA y KERIGMA)
                    $categoria_id = 1;
                    $categoriaNombre = $this->obtenerMejorCategoria($externalConn, $codigo);

                    if (!empty($categoriaNombre)) {
                        if (isset($categoriasCache[$categoriaNombre])) {
                            $categoria_id = $categoriasCache[$categoriaNombre];
                        } else {
                            $catId = $this->obtenerOCrearCategoria($categoriaNombre);
                            $categoriasCache[$categoriaNombre] = $catId;
                            $categoria_id = $catId;
                            $categoriasCreadas++;
                        }
                    }

                    // Obtener almacén e impresora del producto
                    $almacen_id = null;
                    $impresora = null;
                    if (isset($productosAreasMap[$codigo])) {
                        $areaInfo = $productosAreasMap[$codigo];
                        if (isset($almacenesMap[$areaInfo['area_id']])) {
                            $almacen_id = $almacenesMap[$areaInfo['area_id']];
                        }
                        $impresora = $areaInfo['impresora'];
                    }

                    // Procesar cada unidad del producto
                    foreach ($unidades as $index => $row) {
                        $equivalencia = floatval($row['equivalencia'] ?? 1);
                        $unidadKerigma = strtolower(trim($row['unidad'] ?? 'pza'));
                        $esBase = ($equivalencia == 1);

                        // Construir código único: codigo_unidad
                        $codigoProducto = $codigo . '_' . strtoupper($unidadKerigma);

                        // Verificar si ya existe
                        $stmtCheck->bind_param("s", $codigoProducto);
                        $stmtCheck->execute();
                        $checkResult = $stmtCheck->get_result();
                        if ($checkResult->fetch_assoc()) {
                            $omitidos++;
                            continue;
                        }

                        // Construir nombre con unidad si hay más de una
                        $nombreProducto = $nombreBase;
                        if (count($unidades) > 1) {
                            $nombreProducto = $nombreBase . ' (' . strtoupper($unidadKerigma) . ')';
                        }

                        // Obtener precios de tblprecios
                        $precios = $this->obtenerPreciosLista($externalConn, $codigo, $row['unidad'], $equivalencia);

                        // Si no hay precios en tblprecios, usar los de tblundcospreart
                        if ($precios['precio_lista'] == 0) {
                            $precios['precio_lista'] = floatval($row['precio_con_iva'] ?? 0);
                        }
                        if ($precios['precio1'] == 0) {
                            $precios['precio1'] = floatval($row['precio_sin_iva'] ?? $row['precio_con_iva'] ?? 0);
                        }

                        $costoKerigma = floatval($row['costo'] ?? 0);

                        // Validar que tenga al menos precio o costo
                        if ($precios['precio_lista'] <= 0 && $precios['precio1'] <= 0 && $costoKerigma <= 0) {
                            $errores[] = "Producto '$nombreProducto': sin precio ni costo";
                            continue;
                        }

                        // Preparar datos
                        $descripcion = trim($row['descripcion'] ?? '');
                        $codigo_barras = trim($row['codigo_barras'] ?? '');
                        if (empty($codigo_barras)) {
                            $codigo_barras = null;
                        }
                        $cve_cfdi = trim($row['cve_cfdi'] ?? '');
                        if (empty($cve_cfdi)) {
                            $cve_cfdi = null;
                        }

                        $stock = $esBase ? floatval($row['stock'] ?? 0) : 0;
                        $stock_minimo = 0;
                        $unidad = $unidadMap[$unidadKerigma] ?? 'pz';
                        $esBaseFlag = $esBase ? 1 : 0;

                        $stmtInsert->bind_param(
                            "sssssddddddddddsiisi",
                            $nombreProducto,
                            $descripcion,
                            $codigoProducto,
                            $codigo_barras,
                            $cve_cfdi,
                            $costoKerigma,
                            $precios['precio_lista'],
                            $precios['precio1'],
                            $precios['precio2'],
                            $precios['precio3'],
                            $precios['precio4'],
                            $precios['precio5'],
                            $precios['precio6'],
                            $stock,
                            $stock_minimo,
                            $unidad,
                            $categoria_id,
                            $almacen_id,
                            $impresora,
                            $esBaseFlag
                        );

                        if ($stmtInsert->execute()) {
                            $nuevoId = $this->conn->insert_id;
                            $migrados++;

                            // Guardar ID del producto base
                            if ($esBase) {
                                $productoBaseId = $nuevoId;
                            } else if ($productoBaseId !== null) {
                                // Crear equivalencia: este producto contiene X unidades del base
                                // Ej: 1 CJA (nuevoId) = 15 PZA (productoBaseId)
                                $stmtEquivalencia->bind_param("iid", $nuevoId, $productoBaseId, $equivalencia);
                                if ($stmtEquivalencia->execute()) {
                                    $equivalenciasCreadas++;
                                }
                            }
                        } else {
                            $errores[] = "Producto '$nombreProducto': " . $stmtInsert->error;
                        }
                    }
                } catch (Exception $e) {
                    $errores[] = "Error procesando código $codigo: " . $e->getMessage();
                }
            }

            $stmtCheck->close();
            $stmtInsert->close();
            $stmtEquivalencia->close();

            // 4. Migrar descuentos por volumen
            $descuentosMigrados = $this->migrarDescuentosVolumen($externalConn);

            $externalConn->close();

            return [
                'success' => true,
                'message' => "Migración Kerigma completada",
                'data' => [
                    'migrados' => $migrados,
                    'equivalencias' => $equivalenciasCreadas,
                    'omitidos' => $omitidos,
                    'almacenes' => $almacenesMigrados,
                    'categorias' => $categoriasCreadas,
                    'descuentos' => $descuentosMigrados,
                    'errores' => array_slice($errores, 0, 50)
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Obtener o crear categoría por nombre
     */
    private function obtenerOCrearCategoria($nombre)
    {
        $stmt = $this->conn->prepare("SELECT id FROM categorias WHERE nombre = ? LIMIT 1");
        $stmt->bind_param("s", $nombre);
        $stmt->execute();
        $result = $stmt->get_result();

        if ($row = $result->fetch_assoc()) {
            $stmt->close();
            return $row['id'];
        }

        $stmt->close();

        // Crear nueva
        $stmtInsert = $this->conn->prepare("INSERT INTO categorias (nombre, descripcion, activo) VALUES (?, 'Importado de Kerigma', 1)");
        $stmtInsert->bind_param("s", $nombre);
        $stmtInsert->execute();
        $id = $this->conn->insert_id;
        $stmtInsert->close();

        return $id ?: 1;
    }

    /**
     * Preview de migración Kerigma - VERSIÓN COMPLETA
     */
    public function previewMigracionKerigma($data)
    {
        try {
            $host = $data['host'] ?? 'localhost';
            $usuario = $data['usuario'] ?? '';
            $password = $data['password'] ?? '';
            $base_datos = $data['base_datos'] ?? '';
            $limite = $data['limite'] ?? 20;

            $externalConn = new mysqli($host, $usuario, $password, $base_datos);

            if ($externalConn->connect_error) {
                return ['success' => false, 'message' => 'Error de conexión'];
            }

            $externalConn->set_charset("utf8mb4");

            // Contar áreas activas
            $areasCount = 0;
            $areasResult = $externalConn->query("SELECT COUNT(*) as total FROM catalogo_areas WHERE activa = 1");
            if ($areasResult) {
                $areasCount = (int)$areasResult->fetch_assoc()['total'];
            }

            // Contar productos con área asignada
            $productosConArea = 0;
            $prodAreaResult = $externalConn->query("SELECT COUNT(DISTINCT codigo_producto) as total FROM productos_areas WHERE activo = 1");
            if ($prodAreaResult) {
                $productosConArea = (int)$prodAreaResult->fetch_assoc()['total'];
            }

            // Contar listas de precios
            $listasPrecios = 0;
            $listasResult = $externalConn->query("SELECT COUNT(*) as total FROM tbllistasprecios");
            if ($listasResult) {
                $listasPrecios = (int)$listasResult->fetch_assoc()['total'];
            }

            // Contar descuentos por volumen
            $descuentosVolumen = 0;
            $descResult = $externalConn->query("SELECT COUNT(*) as total FROM tblprecvolum WHERE CAN_VOL > 0");
            if ($descResult) {
                $descuentosVolumen = (int)$descResult->fetch_assoc()['total'];
            }

            // Query para preview con mejor categoría
            $query = "
                SELECT
                    a.COD1_ART as codigo,
                    a.DES1_ART as nombre,
                    a.EXI_ACT as stock,
                    u.PRE_IVA as precio,
                    u.COS_UCO as costo,
                    u.COD_UND as unidad,
                    (SELECT c2.DES_AGR
                     FROM tblgpoarticulos g2
                     INNER JOIN tblcatagrupacionart c2 ON g2.COD_AGR = c2.COD_AGR
                     WHERE g2.COD1_ART = a.COD1_ART
                     AND c2.DES_AGR NOT IN ('DEL SISTEMA', 'KERIGMA')
                     LIMIT 1) as categoria,
                    (SELECT ca.nombre_area
                     FROM productos_areas pa
                     INNER JOIN catalogo_areas ca ON pa.area_id = ca.id
                     WHERE pa.codigo_producto = a.COD1_ART AND pa.activo = 1
                     LIMIT 1) as almacen
                FROM tblcatarticulos a
                LEFT JOIN tblundcospreart u ON a.COD1_ART = u.COD1_ART AND u.EQV_UND = 1
                WHERE a.DES1_ART IS NOT NULL AND a.DES1_ART != ''
                GROUP BY a.COD1_ART
                LIMIT " . (int)$limite;

            $result = $externalConn->query($query);
            $preview = [];

            if ($result) {
                while ($row = $result->fetch_assoc()) {
                    $preview[] = $row;
                }
            }

            // Contar total de productos
            $countResult = $externalConn->query("SELECT COUNT(DISTINCT COD1_ART) as total FROM tblcatarticulos WHERE DES1_ART IS NOT NULL AND DES1_ART != ''");
            $total = 0;
            if ($countResult) {
                $countRow = $countResult->fetch_assoc();
                $total = (int)$countRow['total'];
            }

            // Contar unidades totales (productos con equivalencias)
            $unidadesResult = $externalConn->query("SELECT COUNT(*) as total FROM tblundcospreart");
            $totalUnidades = 0;
            if ($unidadesResult) {
                $totalUnidades = (int)$unidadesResult->fetch_assoc()['total'];
            }

            $externalConn->close();

            return [
                'success' => true,
                'data' => [
                    'preview' => $preview,
                    'total' => $total,
                    'totalUnidades' => $totalUnidades,
                    'areasDisponibles' => $areasCount,
                    'productosConArea' => $productosConArea,
                    'listasPrecios' => $listasPrecios,
                    'descuentosVolumen' => $descuentosVolumen
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Ejecutar la migración de productos (genérica)
     */
    public function ejecutarMigracion($data)
    {
        try {
            $host = $data['host'] ?? 'localhost';
            $usuario = $data['usuario'] ?? '';
            $password = $data['password'] ?? '';
            $base_datos = $data['base_datos'] ?? '';
            $tabla = $data['tabla'] ?? '';
            $mapeo = $data['mapeo'] ?? [];

            if (empty($tabla) || empty($mapeo)) {
                return ['success' => false, 'message' => 'Tabla y mapeo son requeridos'];
            }

            // Verificar campos requeridos
            if (empty($mapeo['nombre']) || empty($mapeo['precio1'])) {
                return ['success' => false, 'message' => 'Los campos Nombre y Precio 1 son requeridos'];
            }

            $externalConn = new mysqli($host, $usuario, $password, $base_datos);

            if ($externalConn->connect_error) {
                return ['success' => false, 'message' => 'Error de conexión externa'];
            }

            $externalConn->set_charset("utf8mb4");

            // Construir query para obtener todos los registros
            $selectFields = [];
            foreach ($mapeo as $campoDestino => $columnaOrigen) {
                if (!empty($columnaOrigen)) {
                    $selectFields[] = "`" . $externalConn->real_escape_string($columnaOrigen) . "` AS `" . $campoDestino . "`";
                }
            }

            $query = "SELECT " . implode(", ", $selectFields) . " FROM `" . $externalConn->real_escape_string($tabla) . "`";
            $result = $externalConn->query($query);

            if (!$result) {
                return ['success' => false, 'message' => 'Error al leer datos: ' . $externalConn->error];
            }

            $migrados = 0;
            $omitidos = 0;
            $errores = [];

            // Obtener o crear categoría por defecto
            $categoriaDefault = $this->obtenerCategoriaDefault();

            // Preparar statement para verificar duplicados
            $stmtCheck = $this->conn->prepare("SELECT id FROM productos WHERE codigo_corto = ? OR (nombre = ? AND codigo_barras = ?) LIMIT 1");

            // Preparar statement para insertar productos
            $stmtInsert = $this->conn->prepare("
                INSERT INTO productos (
                    nombre, descripcion, codigo_corto, codigo_barras,
                    precio_compra, precio_lista, precio1, precio2, precio3, precio4, precio5, precio6,
                    stock, stock_minimo, unidad_medida, categoria_id, activo
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)
            ");

            // Preparar statement para buscar categoría por nombre
            $stmtCategoria = $this->conn->prepare("SELECT id FROM categorias WHERE nombre = ? LIMIT 1");

            while ($row = $result->fetch_assoc()) {
                try {
                    // Validar datos mínimos
                    $nombre = trim($row['nombre'] ?? '');
                    if (empty($nombre)) {
                        $errores[] = "Registro sin nombre válido";
                        continue;
                    }

                    $precio1 = floatval($row['precio1'] ?? 0);
                    if ($precio1 <= 0) {
                        $errores[] = "Producto '$nombre': precio inválido";
                        continue;
                    }

                    // Preparar datos
                    $descripcion = trim($row['descripcion'] ?? '');
                    $codigo_corto = trim($row['codigo_corto'] ?? '');
                    $codigo_barras = trim($row['codigo_barras'] ?? '');

                    // Verificar duplicados
                    if (!empty($codigo_corto)) {
                        $stmtCheck->bind_param("sss", $codigo_corto, $nombre, $codigo_barras);
                        $stmtCheck->execute();
                        if ($stmtCheck->get_result()->fetch_assoc()) {
                            $omitidos++;
                            continue;
                        }
                    }

                    $precio_compra = floatval($row['precio_compra'] ?? 0);
                    $precio_lista = floatval($row['precio_lista'] ?? $precio1);
                    $precio2 = floatval($row['precio2'] ?? 0);
                    $precio3 = floatval($row['precio3'] ?? 0);
                    $precio4 = floatval($row['precio4'] ?? 0);
                    $precio5 = floatval($row['precio5'] ?? 0);
                    $precio6 = floatval($row['precio6'] ?? 0);
                    $stock = floatval($row['stock'] ?? 0);
                    $stock_minimo = floatval($row['stock_minimo'] ?? 0);
                    $unidad_medida = trim($row['unidad_medida'] ?? 'pz');

                    // Buscar o asignar categoría
                    $categoria_id = $categoriaDefault;
                    if (!empty($row['categoria_nombre'])) {
                        $categoriaNombre = trim($row['categoria_nombre']);
                        $stmtCategoria->bind_param("s", $categoriaNombre);
                        $stmtCategoria->execute();
                        $catResult = $stmtCategoria->get_result();
                        if ($catRow = $catResult->fetch_assoc()) {
                            $categoria_id = $catRow['id'];
                        } else {
                            // Crear categoría si no existe
                            $nuevaCat = $this->crearCategoria($categoriaNombre);
                            if ($nuevaCat) {
                                $categoria_id = $nuevaCat;
                            }
                        }
                    }

                    // Insertar producto
                    $stmtInsert->bind_param(
                        "ssssddddddddddsi",
                        $nombre,
                        $descripcion,
                        $codigo_corto,
                        $codigo_barras,
                        $precio_compra,
                        $precio_lista,
                        $precio1,
                        $precio2,
                        $precio3,
                        $precio4,
                        $precio5,
                        $precio6,
                        $stock,
                        $stock_minimo,
                        $unidad_medida,
                        $categoria_id
                    );

                    if ($stmtInsert->execute()) {
                        $migrados++;
                    } else {
                        $errores[] = "Producto '$nombre': " . $stmtInsert->error;
                    }
                } catch (Exception $e) {
                    $errores[] = "Error procesando registro: " . $e->getMessage();
                }
            }

            $stmtCheck->close();
            $stmtInsert->close();
            $stmtCategoria->close();
            $externalConn->close();

            return [
                'success' => true,
                'message' => "Migración completada: $migrados productos migrados",
                'data' => [
                    'migrados' => $migrados,
                    'omitidos' => $omitidos,
                    'errores' => $errores
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Obtener o crear categoría por defecto
     */
    private function obtenerCategoriaDefault()
    {
        $result = $this->conn->query("SELECT id FROM categorias WHERE nombre = 'Sin Categoría' OR nombre = 'General' LIMIT 1");
        if ($result && $row = $result->fetch_assoc()) {
            return $row['id'];
        }

        // Crear categoría por defecto
        $this->conn->query("INSERT INTO categorias (nombre, descripcion, activo) VALUES ('General', 'Categoría general para productos migrados', 1)");
        return $this->conn->insert_id;
    }

    /**
     * Crear una nueva categoría
     */
    private function crearCategoria($nombre)
    {
        $stmt = $this->conn->prepare("INSERT INTO categorias (nombre, descripcion, activo) VALUES (?, 'Categoría importada', 1)");
        $stmt->bind_param("s", $nombre);

        if ($stmt->execute()) {
            $id = $this->conn->insert_id;
            $stmt->close();
            return $id;
        }

        $stmt->close();
        return null;
    }

    /**
     * Preview de migración de clientes desde Kerigma
     */
    public function previewMigracionClientesKerigma($data)
    {
        try {
            $host = $data['host'] ?? 'localhost';
            $usuario = $data['usuario'] ?? '';
            $password = $data['password'] ?? '';
            $base_datos = $data['base_datos'] ?? '';
            $limite = $data['limite'] ?? 20;

            $externalConn = new mysqli($host, $usuario, $password, $base_datos);

            if ($externalConn->connect_error) {
                return ['success' => false, 'message' => 'Error de conexión: ' . $externalConn->connect_error];
            }

            $externalConn->set_charset("utf8mb4");

            // Query para preview de clientes
            $query = "
                SELECT
                    COD_CLI as codigo,
                    NOM_CLI as nombre,
                    NOM_COM as nombre_comercial,
                    TEL1_CLI as telefono1,
                    TEL2_CLI as telefono2,
                    MAIL_CLI as email,
                    RFC_CLI as rfc,
                    CONCAT_WS(' ', CALL_NUM, NUM_EXT, COL_CLI, COP_CLI) as direccion,
                    LIM_CRE as limite_credito,
                    PLA_CRE as dias_credito,
                    COD_LISTA as lista_precios,
                    COD_STS as estatus
                FROM tblcatclientes
                WHERE NOM_CLI IS NOT NULL AND NOM_CLI != ''
                ORDER BY COD_CLI
                LIMIT " . (int)$limite;

            $result = $externalConn->query($query);
            $preview = [];

            if ($result) {
                while ($row = $result->fetch_assoc()) {
                    $preview[] = $row;
                }
            }

            // Contar total de clientes
            $countResult = $externalConn->query("SELECT COUNT(*) as total FROM tblcatclientes WHERE NOM_CLI IS NOT NULL AND NOM_CLI != ''");
            $total = 0;
            if ($countResult) {
                $countRow = $countResult->fetch_assoc();
                $total = (int)$countRow['total'];
            }

            // Contar clientes con teléfono
            $telResult = $externalConn->query("SELECT COUNT(*) as total FROM tblcatclientes WHERE (TEL1_CLI IS NOT NULL AND TEL1_CLI != '') OR (TEL2_CLI IS NOT NULL AND TEL2_CLI != '')");
            $conTelefono = 0;
            if ($telResult) {
                $conTelefono = (int)$telResult->fetch_assoc()['total'];
            }

            // Contar clientes con RFC
            $rfcResult = $externalConn->query("SELECT COUNT(*) as total FROM tblcatclientes WHERE RFC_CLI IS NOT NULL AND RFC_CLI != ''");
            $conRfc = 0;
            if ($rfcResult) {
                $conRfc = (int)$rfcResult->fetch_assoc()['total'];
            }

            // Contar clientes con dirección
            $dirResult = $externalConn->query("SELECT COUNT(*) as total FROM tblcatclientes WHERE (CALL_NUM IS NOT NULL AND CALL_NUM != '') OR (COL_CLI IS NOT NULL AND COL_CLI != '')");
            $conDireccion = 0;
            if ($dirResult) {
                $conDireccion = (int)$dirResult->fetch_assoc()['total'];
            }

            $externalConn->close();

            return [
                'success' => true,
                'data' => [
                    'preview' => $preview,
                    'total' => $total,
                    'conTelefono' => $conTelefono,
                    'conRfc' => $conRfc,
                    'conDireccion' => $conDireccion
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Preview de diferencia de costos desde BD local (pos_abarrotes)
     */
    public function previewDiferenciaCostos($data)
    {
        try {
            $limite = $data['limite'] ?? 20;

            // Verificar que existe la tabla diferencia_costos
            $checkTable = $this->conn->query("SHOW TABLES LIKE 'diferencia_costos'");
            if ($checkTable->num_rows === 0) {
                return ['success' => false, 'message' => 'La tabla diferencia_costos no existe en la base de datos'];
            }

            // Query para preview
            $query = "SELECT producto_id, descripcion, costo_para_calculo, costo_pacific_soft, costo_mayor, importe_diferencia FROM diferencia_costos LIMIT " . (int)$limite;

            $result = $this->conn->query($query);
            $preview = [];

            if ($result) {
                while ($row = $result->fetch_assoc()) {
                    $preview[] = $row;
                }
            }

            // Contar total
            $countResult = $this->conn->query("SELECT COUNT(*) as total FROM diferencia_costos");
            $total = 0;
            if ($countResult) {
                $total = (int)$countResult->fetch_assoc()['total'];
            }

            return [
                'success' => true,
                'data' => [
                    'preview' => $preview,
                    'total' => $total
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Ejecutar actualización de costos desde diferencia_costos (BD local)
     * Actualiza precio_compra y costo_precios en productos
     * Vínculo: diferencia_costos.producto_id -> productos.codigo_corto (sin sufijo)
     * Solo actualiza productos con equivalencia (cajas)
     */
    public function ejecutarActualizacionCostos($data)
    {
        try {
            // Leer todos los registros de diferencia_costos desde BD local
            $result = $this->conn->query("SELECT producto_id, descripcion, costo_para_calculo FROM diferencia_costos WHERE costo_para_calculo > 0");

            if (!$result) {
                return ['success' => false, 'message' => 'Error al leer diferencia_costos: ' . $this->conn->error];
            }

            $actualizados = 0;
            $noEncontrados = 0;
            $errores = [];

            // Preparar statement para buscar producto con equivalencia
            $stmtBuscar = $this->conn->prepare("
                SELECT p.id
                FROM productos p
                INNER JOIN producto_equivalencias pe ON pe.producto_id = p.id
                WHERE SUBSTRING_INDEX(p.codigo_corto, '_', 1) = ?
                LIMIT 1
            ");

            // Preparar statement para actualizar costos
            $stmtUpdate = $this->conn->prepare("
                UPDATE productos SET precio_compra = ?, costo_precios = ? WHERE id = ?
            ");

            while ($row = $result->fetch_assoc()) {
                try {
                    $productoId = trim($row['producto_id']);
                    $costoCalculo = floatval($row['costo_para_calculo']);

                    // Buscar producto con equivalencia
                    $stmtBuscar->bind_param("s", $productoId);
                    $stmtBuscar->execute();
                    $buscarResult = $stmtBuscar->get_result();

                    if ($prodRow = $buscarResult->fetch_assoc()) {
                        $localId = $prodRow['id'];

                        // Actualizar precio_compra y costo_precios
                        $stmtUpdate->bind_param("ddi", $costoCalculo, $costoCalculo, $localId);
                        if ($stmtUpdate->execute()) {
                            $actualizados++;
                        } else {
                            $errores[] = "Producto '$productoId': " . $stmtUpdate->error;
                        }
                    } else {
                        $noEncontrados++;
                    }
                } catch (Exception $e) {
                    $errores[] = "Error procesando '$productoId': " . $e->getMessage();
                }
            }

            $stmtBuscar->close();
            $stmtUpdate->close();

            return [
                'success' => true,
                'message' => "Actualización de costos completada",
                'data' => [
                    'actualizados' => $actualizados,
                    'noEncontrados' => $noEncontrados,
                    'errores' => array_slice($errores, 0, 50)
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }

    /**
     * Ejecutar migración de clientes desde Kerigma
     */
    public function ejecutarMigracionClientesKerigma($data)
    {
        try {
            $host = $data['host'] ?? 'localhost';
            $usuario = $data['usuario'] ?? '';
            $password = $data['password'] ?? '';
            $base_datos = $data['base_datos'] ?? '';

            $externalConn = new mysqli($host, $usuario, $password, $base_datos);

            if ($externalConn->connect_error) {
                return ['success' => false, 'message' => 'Error de conexión externa: ' . $externalConn->connect_error];
            }

            $externalConn->set_charset("utf8mb4");

            // Query para obtener todos los clientes
            $query = "
                SELECT
                    COD_CLI,
                    NOM_CLI,
                    NOM_COM,
                    TEL1_CLI,
                    TEL2_CLI,
                    MAIL_CLI,
                    RFC_CLI,
                    CALL_NUM,
                    NUM_EXT,
                    NUM_INT,
                    COL_CLI,
                    COP_CLI,
                    LIM_CRE,
                    PLA_CRE,
                    COD_LISTA,
                    COD_STS
                FROM tblcatclientes
                WHERE NOM_CLI IS NOT NULL AND NOM_CLI != ''
                ORDER BY COD_CLI
            ";

            $result = $externalConn->query($query);

            if (!$result) {
                return ['success' => false, 'message' => 'Error al leer clientes: ' . $externalConn->error];
            }

            $clientesMigrados = 0;
            $telefonosMigrados = 0;
            $direccionesMigradas = 0;
            $datosFiscalesMigrados = 0;
            $omitidos = 0;
            $errores = [];

            // Preparar statements
            // Verificar por nombre para evitar duplicados
            $stmtCheckCliente = $this->conn->prepare("SELECT id FROM clientes WHERE nombre = ? LIMIT 1");

            // La tabla clientes incluye campos fiscales directamente
            $stmtInsertCliente = $this->conn->prepare("
                INSERT INTO clientes (
                    nombre, nombre_comercial, precio_venta, activo,
                    tiene_credito, monto_credito_maximo, dias_credito,
                    rfc, razon_social, email_facturacion
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");

            // cliente_telefonos: tipo es ENUM('principal','casa','trabajo','otro')
            $stmtInsertTelefono = $this->conn->prepare("
                INSERT INTO cliente_telefonos (cliente_id, telefono, tipo, whatsapp, activo)
                VALUES (?, ?, ?, 0, 1)
            ");

            // cliente_direcciones: tipo es ENUM('principal','entrega','facturacion','otro')
            $stmtInsertDireccion = $this->conn->prepare("
                INSERT INTO cliente_direcciones (cliente_id, direccion, tipo, activo)
                VALUES (?, ?, 'principal', 1)
            ");

            // cliente_datos_fiscales: insertar con valores por defecto para campos requeridos
            $stmtInsertDatosFiscales = $this->conn->prepare("
                INSERT INTO cliente_datos_fiscales (
                    cliente_id, rfc, razon_social, regimen_fiscal, uso_cfdi,
                    codigo_postal_fiscal, email_facturacion, es_principal, activo
                ) VALUES (?, ?, ?, ?, 'G03', ?, ?, 1, 1)
            ");

            while ($row = $result->fetch_assoc()) {
                try {
                    $nombre = trim($row['NOM_CLI'] ?? '');

                    if (empty($nombre)) {
                        continue;
                    }

                    // Verificar si ya existe por nombre
                    $stmtCheckCliente->bind_param("s", $nombre);
                    $stmtCheckCliente->execute();
                    if ($stmtCheckCliente->get_result()->fetch_assoc()) {
                        $omitidos++;
                        continue;
                    }

                    // Preparar datos del cliente
                    $nombreComercial = trim($row['NOM_COM'] ?? '');
                    $rfc = strtoupper(trim($row['RFC_CLI'] ?? ''));
                    $email = trim($row['MAIL_CLI'] ?? '');
                    $limiteCredito = floatval($row['LIM_CRE'] ?? 0);
                    $diasCredito = intval($row['PLA_CRE'] ?? 0);
                    $listaPrecios = intval($row['COD_LISTA'] ?? 1);
                    $estatus = intval($row['COD_STS'] ?? 1);
                    $activo = ($estatus == 1) ? 1 : 0;
                    $tieneCredito = ($limiteCredito > 0) ? 1 : 0;

                    // Validar email
                    if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
                        $email = null;
                    }

                    // Mapear lista de precios de Kerigma a precio_venta
                    $precioVentaMap = [
                        1 => 'precio1',
                        2 => 'precio2',
                        3 => 'precio3',
                        4 => 'precio4',
                        5 => 'precio5',
                        6 => 'precio6'
                    ];
                    $precioVenta = $precioVentaMap[$listaPrecios] ?? 'precio1';

                    // Razon social para datos fiscales
                    $razonSocial = !empty($nombreComercial) ? $nombreComercial : $nombre;

                    // Insertar cliente (incluye datos fiscales básicos en la misma tabla)
                    $stmtInsertCliente->bind_param(
                        "sssiidisss",
                        $nombre,
                        $nombreComercial,
                        $precioVenta,
                        $activo,
                        $tieneCredito,
                        $limiteCredito,
                        $diasCredito,
                        $rfc,
                        $razonSocial,
                        $email
                    );

                    if ($stmtInsertCliente->execute()) {
                        $clienteId = $this->conn->insert_id;
                        $clientesMigrados++;

                        // Insertar teléfonos
                        $tel1 = trim($row['TEL1_CLI'] ?? '');
                        $tel2 = trim($row['TEL2_CLI'] ?? '');

                        if (!empty($tel1)) {
                            $tipoPrincipal = 'principal';
                            $stmtInsertTelefono->bind_param("iss", $clienteId, $tel1, $tipoPrincipal);
                            if ($stmtInsertTelefono->execute()) {
                                $telefonosMigrados++;
                            }
                        }

                        if (!empty($tel2) && $tel2 !== $tel1) {
                            $tipoOtro = 'otro';
                            $stmtInsertTelefono->bind_param("iss", $clienteId, $tel2, $tipoOtro);
                            if ($stmtInsertTelefono->execute()) {
                                $telefonosMigrados++;
                            }
                        }

                        // Construir dirección completa como texto único
                        $calle = trim($row['CALL_NUM'] ?? '');
                        $numExt = trim($row['NUM_EXT'] ?? '');
                        $numInt = trim($row['NUM_INT'] ?? '');
                        $colonia = trim($row['COL_CLI'] ?? '');
                        $cp = trim($row['COP_CLI'] ?? '');

                        // Concatenar dirección
                        $partsDireccion = [];
                        if (!empty($calle)) $partsDireccion[] = $calle;
                        if (!empty($numExt)) $partsDireccion[] = "No. " . $numExt;
                        if (!empty($numInt)) $partsDireccion[] = "Int. " . $numInt;
                        if (!empty($colonia)) $partsDireccion[] = "Col. " . $colonia;
                        if (!empty($cp)) $partsDireccion[] = "C.P. " . $cp;

                        $direccionCompleta = implode(', ', $partsDireccion);

                        if (!empty($direccionCompleta)) {
                            $stmtInsertDireccion->bind_param("is", $clienteId, $direccionCompleta);
                            if ($stmtInsertDireccion->execute()) {
                                $direccionesMigradas++;
                            }
                        }

                        // Insertar datos fiscales si tiene RFC válido (no genérico)
                        if (!empty($rfc) && $rfc !== 'XAXX010101000' && $rfc !== 'XEXX010101000') {
                            // Determinar régimen fiscal por defecto basado en longitud del RFC
                            // RFC 12 caracteres = Persona Moral (601)
                            // RFC 13 caracteres = Persona Física (612)
                            $regimenFiscal = (strlen($rfc) == 12) ? '601' : '612';

                            // Código postal de la dirección o valor por defecto
                            $cpFiscal = !empty($cp) ? substr($cp, 0, 5) : '00000';

                            // Email para facturación
                            $emailFact = !empty($email) ? $email : '';

                            $stmtInsertDatosFiscales->bind_param(
                                "isssss",
                                $clienteId,
                                $rfc,
                                $razonSocial,
                                $regimenFiscal,
                                $cpFiscal,
                                $emailFact
                            );
                            if ($stmtInsertDatosFiscales->execute()) {
                                $datosFiscalesMigrados++;
                            }
                        }

                    } else {
                        $errores[] = "Cliente '$nombre': " . $stmtInsertCliente->error;
                    }
                } catch (Exception $e) {
                    $errores[] = "Error procesando cliente: " . $e->getMessage();
                }
            }

            $stmtCheckCliente->close();
            $stmtInsertCliente->close();
            $stmtInsertTelefono->close();
            $stmtInsertDireccion->close();
            $stmtInsertDatosFiscales->close();
            $externalConn->close();

            return [
                'success' => true,
                'message' => "Migración de clientes completada",
                'data' => [
                    'clientesMigrados' => $clientesMigrados,
                    'telefonosMigrados' => $telefonosMigrados,
                    'direccionesMigradas' => $direccionesMigradas,
                    'datosFiscalesMigrados' => $datosFiscalesMigrados,
                    'omitidos' => $omitidos,
                    'errores' => array_slice($errores, 0, 50)
                ]
            ];
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
        }
    }
}

// Procesar solicitudes
$migracion = new Migracion($conn);

switch ($tipo) {
    case 'probarConexionExterna':
        echo json_encode($migracion->probarConexion($datapost));
        break;

    case 'obtenerColumnasTabla':
        echo json_encode($migracion->obtenerColumnas($datapost));
        break;

    case 'previewMigracion':
        echo json_encode($migracion->previewMigracion($datapost));
        break;

    case 'ejecutarMigracionProductos':
        echo json_encode($migracion->ejecutarMigracion($datapost));
        break;

    case 'previewMigracionKerigma':
        echo json_encode($migracion->previewMigracionKerigma($datapost));
        break;

    case 'ejecutarMigracionKerigma':
        echo json_encode($migracion->ejecutarMigracionKerigma($datapost));
        break;

    case 'previewMigracionClientesKerigma':
        echo json_encode($migracion->previewMigracionClientesKerigma($datapost));
        break;

    case 'ejecutarMigracionClientesKerigma':
        echo json_encode($migracion->ejecutarMigracionClientesKerigma($datapost));
        break;

    case 'previewDiferenciaCostos':
        echo json_encode($migracion->previewDiferenciaCostos($datapost));
        break;

    case 'ejecutarActualizacionCostos':
        echo json_encode($migracion->ejecutarActualizacionCostos($datapost));
        break;

    default:
        echo json_encode(['success' => false, 'message' => 'Operación no válida']);
}
