<?php
// ─── 1) CONFIG DB ────────────────────────────────────────────
define('DB_SERVER',   'localhost');
define('DB_USERNAME', 'ndconsulta');
define('DB_PASSWORD', 'Nitro2021');
define('DB_NAME',     'db_compranet');

// ─── 2) OPENAI KEY ───────────────────────────────────────────
define('OPENAI_API_KEY', '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');

// ─── 3) RUTA LOG para errores ─────────────────────────────────
$logFile = __DIR__ . '/generate_envios.log';

// ─── 4) FUNCIÓN genérica para llamar al modelo ───────────────
function callOpenAI(array $messages, array $functions, string $fn)
{
    $payload = [
        'model'         => 'gpt-3.5-turbo',
        'messages'      => $messages,
        'functions'     => $functions,
        'function_call' => ['name' => $fn],
        'max_tokens'    => 400,
        'temperature'   => 0.4
    ];
    $ch = curl_init('https://api.openai.com/v1/chat/completions');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer ' . OPENAI_API_KEY,
            'Content-Type: application/json'
        ],
        CURLOPT_POSTFIELDS     => json_encode($payload, JSON_UNESCAPED_UNICODE)
    ]);
    $raw = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    $j = json_decode($raw, true);
    if ($code !== 200 || !isset($j['choices'][0]['message']['function_call'])) {
        error_log("OpenAI error [$code]: " . ($j['error']['message'] ?? $raw) . PHP_EOL, 3, $GLOBALS['logFile']);
        return null;
    }
    return $j['choices'][0]['message']['function_call']['arguments'] ?? null;
}

// ─── 5) CONEXIÓN DB ──────────────────────────────────────────
$conn = new mysqli(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
if ($conn->connect_error) {
    file_put_contents($logFile, "Conexión DB fallida: " . $conn->connect_error . PHP_EOL, FILE_APPEND);
    die("Conexión fallida: " . $conn->connect_error);
}

// ─── 6) PRODUCTOS a procesar ─────────────────────────────────
// Filtra CASE-SENSITIVE: txtEmpaque no contiene "Kg" exactamente
$sql = "
SELECT id, nombre, txtEmpaque
FROM tb_productos
WHERE txtEmpaque IS NOT NULL
  AND LOWER(txtEmpaque) LIKE '%kg%' AND largoCmCaja IS NULL
ORDER BY id ASC
";
$res = $conn->query($sql);
if (!$res) {
    file_put_contents($logFile, "Error SQL (SELECT): " . $conn->error . PHP_EOL, FILE_APPEND);
    die($conn->error);
}

// ─── 7) Esquema function-calling ─────────────────────────────
$fnSchema = [[
    'name'        => 'parse_empaque',
    'description' => 'Extrae medidas de caja al por mayor (tres dimensiones en cm), unidades por caja y peso total de la caja en kg. ' .
        'Si aparece "Peso Bruto", usar ese valor; si solo aparece "Peso" o "Peso Neto", asumirlo como bruto. ' .
        'Devuelve JSON con campos: undsCaja (int), dim1 (number), dim2 (number), dim3 (number), pesoKgCaja (number).',
    'parameters'  => [
        'type'       => 'object',
        'properties' => [
            'undsCaja'    => ['type' => 'integer'],
            'dim1'        => ['type' => 'number'],
            'dim2'        => ['type' => 'number'],
            'dim3'        => ['type' => 'number'],
            'pesoKgCaja'  => ['type' => 'number']
        ],
        'required' => ['undsCaja', 'dim1', 'dim2', 'dim3', 'pesoKgCaja']
    ]
]];

// ─── 8) LOOP de procesamiento ───────────────────────────────
while ($row = $res->fetch_assoc()) {
    // 8.1 Verificación de id existente
    if (!isset($row['id'])) {
        file_put_contents($logFile, "Fila sin 'id' retornada por SQL, se omite." . PHP_EOL, FILE_APPEND);
        continue;
    }
    $id = (int)$row['id'];
    $nombre = $row['nombre'];
    $txtEmpaque = $row['txtEmpaque'];

    echo "Procesando producto ID $id…\n";

    // 8.2 Prompt para OpenAI
    $msg = [
        [
            'role'    => 'system',
            'content' =>
            "Eres un especialista en logística. Recibe texto de 'txtEmpaque' y devuelve SOLO JSON " .
                "con estos campos: undsCaja (entero), dim1, dim2, dim3 (dimensiones en cm), pesoKgCaja (kg). " .
                "Si en el texto aparece 'Peso Bruto', úsalo; si solo aparece 'Peso' o 'Peso Neto', asume que es bruto. " .
                "Si no encuentras peso de la caja, devuelve un objeto vacío."
        ],
        [
            'role'    => 'user',
            'content' => "Texto de empaque: $txtEmpaque"
        ]
    ];

    $args = callOpenAI($msg, $fnSchema, 'parse_empaque');
    if (!$args) {
        echo "  ⚠️ Error OpenAI o respuesta inválida\n";
        file_put_contents($logFile, "Producto ID $id: Error en respuesta de OpenAI\n", FILE_APPEND);
        continue;
    }

    $d = json_decode($args, true);
    if (
        !$d ||
        !isset($d['undsCaja'], $d['dim1'], $d['dim2'], $d['dim3'], $d['pesoKgCaja'])
    ) {
        echo "  ⚠️ Datos incompletos o faltó peso, OMITIDO\n";
        file_put_contents($logFile, "Producto ID $id: Datos incompletos de OpenAI\n", FILE_APPEND);
        continue;
    }

    // 8.3 Normalizar números: coma→punto y valores <1 multiplicar por 100
    $toNum = function ($v) {
        if ($v === null) return null;
        $f = floatval(str_replace(',', '.', $v));
        return ($f > 0 && $f < 1) ? $f * 100 : $f;
    };

    $undsCajaRaw   = (int)$d['undsCaja'];
    $rawDim1       = $toNum($d['dim1']);
    $rawDim2       = $toNum($d['dim2']);
    $rawDim3       = $toNum($d['dim3']);
    $pesoKgCajaRaw = $toNum($d['pesoKgCaja']);

    if ($undsCajaRaw <= 0 || !$pesoKgCajaRaw || $pesoKgCajaRaw <= 0) {
        echo "  ⚠️ Peso de caja o unidades inválidas, OMITIDO\n";
        file_put_contents($logFile, "Producto ID $id: Peso o unidades inválidas ($undsCajaRaw, $pesoKgCajaRaw)\n", FILE_APPEND);
        continue;
    }

    // 8.4 Ordenar dimensiones para asegurar: largo ≥ ancho ≥ alto
    $dims = [$rawDim1, $rawDim2, $rawDim3];
    rsort($dims);
    $largoCmCaja = round($dims[0], 2);
    $anchoCmCaja = round($dims[1], 2);
    $altoCmCaja  = round($dims[2], 2);

    // 8.5 Redondear otros valores a 2 decimales
    $undsCaja   = $undsCajaRaw;
    $pesoKgCaja = round($pesoKgCajaRaw, 2);

    // 8.6 Extraer tipo_producto de 'nombre' → UNA palabra
    $tipoProd = strtolower(trim($nombre));
    $tipoProd = preg_replace('/\s.*$/', '', $tipoProd);                   // Solo primera palabra
    $tipoProd = iconv('UTF-8', 'ASCII//TRANSLIT', $tipoProd);             // Quitar acentos
    $tipoProd = preg_replace('/[^a-z0-9]/', '', $tipoProd);               // Quitar no alfanuméricos

    if ($tipoProd === '') {
        echo "  ⚠️ No se pudo normalizar tipo_producto, OMITIDO\n";
        file_put_contents($logFile, "Producto ID $id: tipo_producto vacío después de normalizar nombre\n", FILE_APPEND);
        continue;
    }

    // 8.7 Buscar o insertar en tb_tipo_producto
    $stmt = $conn->prepare("SELECT id FROM tb_tipo_producto WHERE nombre = ?");
    $stmt->bind_param('s', $tipoProd);
    if (!$stmt->execute()) {
        file_put_contents($logFile, "SQL error en SELECT tb_tipo_producto: " . $stmt->error . PHP_EOL, FILE_APPEND);
        $stmt->close();
        continue;
    }
    $stmt->bind_result($tipoId);
    $encontrado = $stmt->fetch();
    $stmt->close();

    if (!$encontrado) {
        $stmt = $conn->prepare("INSERT INTO tb_tipo_producto (nombre) VALUES (?)");
        $stmt->bind_param('s', $tipoProd);
        if (!$stmt->execute()) {
            file_put_contents($logFile, "SQL error INSERT tb_tipo_producto: " . $stmt->error . PHP_EOL, FILE_APPEND);
            $stmt->close();
            continue;
        }
        $tipoId = $stmt->insert_id;
        $stmt->close();
        echo "  ✅ Nuevo tipo_producto '$tipoProd' con ID $tipoId\n";
        file_put_contents($logFile, "Producto ID $id: Insertado tipo_producto '$tipoProd' ID $tipoId\n", FILE_APPEND);
    } else {
        echo "  ℹ️ Tipo_producto existente '$tipoProd' con ID $tipoId\n";
        file_put_contents($logFile, "Producto ID $id: Tipo_producto existente ID $tipoId\n", FILE_APPEND);
    }

    // 8.8 Calcular volúmenes y peso por unidad (sin redondear)
    $volumenCm3Caja     = $largoCmCaja * $anchoCmCaja * $altoCmCaja;
    $volumenCm3Producto = $volumenCm3Caja / $undsCaja;
    $pesoKgProducto     = $pesoKgCaja / $undsCaja;

    // 8.9 UPDATE en tb_productos
    $updateSql = "
        UPDATE tb_productos SET
            idTipoProducto       = ?,
            largoCmCaja          = ?,
            anchoCmCaja          = ?,
            altoCmCaja           = ?,
            undsCaja             = ?,
            pesoKgCaja           = ?,
            volumenCm3Caja       = ?,
            volumenCm3Producto   = ?,
            pesoKgProducto       = ?
        WHERE id = ?
    ";
    $stmt = $conn->prepare($updateSql);
    if (!$stmt) {
        file_put_contents($logFile, "SQL error en preparar UPDATE: " . $conn->error . PHP_EOL, FILE_APPEND);
        continue;
    }
    $stmt->bind_param(
        'idddiddddi',
        $tipoId,
        $largoCmCaja,
        $anchoCmCaja,
        $altoCmCaja,
        $undsCaja,
        $pesoKgCaja,
        $volumenCm3Caja,
        $volumenCm3Producto,
        $pesoKgProducto,
        $id
    );
    if ($stmt->execute()) {
        echo "  ✅ Producto ID $id actualizado correctamente\n";
        file_put_contents($logFile, "Producto ID $id: Actualizado OK\n", FILE_APPEND);
    } else {
        echo "  ❌ Error actualizando producto ID $id: " . $stmt->error . "\n";
        file_put_contents($logFile, "Producto ID $id: Error UPDATE: " . $stmt->error . PHP_EOL, FILE_APPEND);
    }
    $stmt->close();

    // Pausa breve para respetar posibles límites
    sleep(1);
}

$conn->close();
echo "Proceso finalizado.\n";
