<?php
// importacionml.php
require __DIR__ . '/../../vendor/autoload.php';
require_once 'config/db.php';

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;

/**
 * 1) Recuperar credenciales más recientes
 */
function getCredentials($conn)
{
    $stmt = $conn->prepare("
        SELECT user_id, access_token, refresh_token, expires_in, updated_at
          FROM tb_marketplace_tokens
         WHERE idMP = 1
         ORDER BY updated_at DESC
         LIMIT 1
    ");
    $stmt->execute();
    $stmt->bind_result($user_id, $access_token, $refresh_token, $expires_in, $updated_at);
    $stmt->fetch();
    $stmt->close();
    return compact('user_id', 'access_token', 'refresh_token', 'expires_in', 'updated_at');
}

/**
 * 2) Refrescar token si va a expirar
 */
function refreshTokenIfNeeded(Client $http, array &$creds, $conn)
{
    $expireTs = strtotime($creds['updated_at']) + $creds['expires_in'];
    if (time() < $expireTs - 60) {
        return;
    }
    $resp = $http->post('/oauth/token', [
        'form_params' => [
            'grant_type'    => 'refresh_token',
            'client_id'     => '3658695067033012',
            'client_secret' => 'GZBg63xJNM9Eeb2cOhF9JwsOEv6vTxo7',
            'refresh_token' => $creds['refresh_token'],
        ],
        'headers' => ['Accept' => 'application/json'],
    ]);
    $data = json_decode($resp->getBody(), true);

    // Actualizar credenciales en $creds y en la BD
    $creds['access_token']  = $data['access_token'];
    $creds['refresh_token'] = $data['refresh_token'];
    $creds['expires_in']    = $data['expires_in'];

    $u = $conn->prepare("
        UPDATE tb_marketplace_tokens
           SET access_token = ?, refresh_token = ?, expires_in = ?, updated_at = NOW()
         WHERE user_id = ?
    ");
    $u->bind_param(
        'ssis',
        $creds['access_token'],
        $creds['refresh_token'],
        $creds['expires_in'],
        $creds['user_id']
    );
    $u->execute();
    $u->close();
}

/**
 * 3) Sincronizar TODOS los ítems con visualización de avance

 */

/**
 * Obtiene y cachea los listing_prices, con retries en 429.
 */
function getListingPrices(Client $http, string $token, float $price, string $category_id)
{
    static $cache = [];

    $key = "{$price}|{$category_id}";
    if (isset($cache[$key])) {
        return $cache[$key];
    }

    $attempts   = 0;
    $maxRetries = 5;
    $delay      = 1; // segundos inicial

    do {
        try {
            $response = $http->get('/sites/MCO/listing_prices', [
                'headers' => ['Accept' => 'application/json'],
                'query'   => ['price' => $price, 'category_id' => $category_id],
            ]);
            $data = json_decode($response->getBody(), true);
            // normalizar a array de detalles:
            if (isset($data['listing_type_id'])) {
                $data = [$data];
            }
            return $cache[$key] = $data;
        } catch (ClientException $e) {
            $resp = $e->getResponse();
            if ($resp && $resp->getStatusCode() === 429 && $attempts < $maxRetries) {
                // usar Retry-After si existe, o back-off exponencial
                $ra = $resp->getHeaderLine('Retry-After');
                sleep($ra ? (int)$ra : $delay);
                $delay *= 2;
                $attempts++;
                continue;
            }
            // si no es 429 o agotamos retries, relanzar
            throw $e;
        }
    } while ($attempts <= $maxRetries);

    // nunca debería llegar aquí
    throw new RuntimeException("No se pudo obtener listing_prices para {$key}");
}

function importacionSync($conn)
{
    // credenciales y cliente HTTP
    $creds = getCredentials($conn);
    if (empty($creds['access_token'])) {
        die("No hay token en tb_marketplace_tokens. Ejecuta authorize.php primero.\n");
    }
    $http = new Client([
        'base_uri' => 'https://api.mercadolibre.com',
        'timeout'  => 30,
    ]);
    session_start();
    refreshTokenIfNeeded($http, $creds, $conn);

    $token = $creds['access_token'];
    $user  = $creds['user_id'];
    $limit = 50;

    echo "Iniciando sincronización de productos...\n";
    $processed = 0;

    // 3.1) Reset de flags de importación
    $conn->query("
      UPDATE tb_marketplace_productos
         SET checkImport = 0
       WHERE idMarketplace = 1
    ");
    $conn->query("
      UPDATE tb_marketplace_variantes mv
        JOIN tb_marketplace_productos mp
          ON mv.idMarketplaceProducto = mp.id
         AND mp.idMarketplace = 1
       SET mv.checkImport = 0
    ");

    // 3.2) Borrar logs previos de esta instancia
    $conn->query("DELETE FROM tb_marketplace_logs WHERE idMarketplace = 1 AND instancia = 'importación'");

    // prepare para bucle de scroll
    $resp = $http->get("/users/{$user}/items/search", [
        'headers' => [
            'Authorization' => "Bearer {$token}",
            'Accept'        => 'application/json',
        ],
        'query' => [
            'search_type' => 'scan',
            'limit'       => $limit,
        ],
    ]);
    $data     = json_decode($resp->getBody(), true);
    $results  = $data['results'] ?? [];
    $scrollId = $data['scroll_id'] ?? null;

    // contenedor para batch de variantes
    $variantUpdates = [];

    // 3.3) Loop de scroll con progreso
    while (!empty($results)) {
        $chunks = array_chunk($results, 20);
        foreach ($chunks as $c) {
            $batchResp = $http->get('/items', [
                'headers' => [
                    'Authorization' => "Bearer {$token}",
                    'Accept'        => 'application/json',
                ],
                'query' => ['ids' => implode(',', $c)],
            ]);
            $batch = json_decode($batchResp->getBody(), true);
            foreach ($batch as $entry) {
                syncProduct($conn, $entry['body'], $http, $token, $variantUpdates);
                $processed++;
                echo "Productos sincronizados: {$processed}\n";
            }
        }
        if (!$scrollId) {
            break;
        }
        $resp = $http->get("/users/{$user}/items/search", [
            'headers' => [
                'Authorization' => "Bearer {$token}",
                'Accept'        => 'application/json',
            ],
            'query' => [
                'search_type' => 'scan',
                'limit'       => $limit,
                'scroll_id'   => $scrollId,
            ],
        ]);
        $data     = json_decode($resp->getBody(), true);
        $results  = $data['results'] ?? [];
        $scrollId = $data['scroll_id'] ?? null;
    }

    // 4) Bulk update de variantes existentes
    if (!empty($variantUpdates)) {
        $caseStock = $casePrice = $caseColor = '';
        $refs      = [];
        foreach ($variantUpdates as $u) {
            $r = $conn->real_escape_string($u['ref']);
            $refs[] = "'{$r}'";
            $caseStock .= " WHEN '{$r}' THEN {$u['stock']}";
            $casePrice .= " WHEN '{$r}' THEN {$u['price']}";
            $escapedColor = $conn->real_escape_string($u['color']);
            $caseColor .= " WHEN '{$r}' THEN '{$escapedColor}'";
        }
        $inList = implode(',', $refs);

        $sql = "
        UPDATE tb_marketplace_variantes mv
        JOIN tb_marketplace_productos mp
          ON mv.idMarketplaceProducto = mp.id
         AND mp.idMarketplace = 1
        SET
          mv.stockActualMP    = CASE mv.refMPVariante {$caseStock} END,
          mv.precioActualMP   = CASE mv.refMPVariante {$casePrice} END,
          mv.colorActualMP    = CASE mv.refMPVariante {$caseColor} END,
          mv.checkImport      = 1
        WHERE mv.refMPVariante IN ({$inList})
        ";
        $conn->query($sql);
    }

    echo "Sincronización completada. Total de productos procesados: {$processed}\n";
}

/**
 * 5) Sincronizar un producto, mapear estado y coleccionar variantes
 */
function syncProduct($conn, array $p, Client $http, $token, array &$variantUpdates)
{
    global $conn;
    $id          = $p['id'];
    $title       = $p['title'] ?? '';
    $category_id = $p['category_id'] ?? '';
    $price       = (float) ($p['price'] ?? 0);
    $sold_qty    = (int)   ($p['sold_quantity'] ?? 0);
    $stock       = (int)   ($p['available_quantity'] ?? 0);

    // Mapear estado de MercadoLibre a idEstadoMP
    $status = $p['status'] ?? '';
    switch ($status) {
        case 'active':
            $idEstadoMP = 1;
            break;
        case 'paused':
            $idEstadoMP = 2;
            break;
        case 'under_review':
            $idEstadoMP = 3;
            break;
        default:
            $idEstadoMP = 0;
    }

    // obtener descripción
    try {
        $descResp    = $http->get("/items/{$id}/description", [
            'headers' => ['Authorization' => "Bearer {$token}", 'Accept' => 'application/json'],
        ]);
        $descData    = json_decode($descResp->getBody(), true);
        $description = $descData['plain_text'] ?? '';
    } catch (ClientException $e) {
        $description = '';
    }

    // obtener fees
    $lpResp = $http->get('/sites/MCO/listing_prices', [
        'query'   => ['price' => $price, 'category_id' => $category_id],
        'headers' => ['Accept' => 'application/json'],
    ]);
    $lpData = getListingPrices($http, $token, $price, $category_id);
    $first = $lpData[0] ?? [];
    $first          = $lpData[0] ?? [];
    $details        = $first['sale_fee_details'] ?? [];
    $fixed_fee      = (float) ($details['fixed_fee']    ?? 0);
    $percentage_fee = (float) ($details['percentage_fee'] ?? 0);

    // 5.1) Actualizar o loguear producto
    $sel = $conn->prepare("
        SELECT tituloPublicacion, descripcionPublicacion
          FROM tb_marketplace_productos
         WHERE idMarketplace = 1
           AND refMP = ?
    ");
    $sel->bind_param('s', $id);
    $sel->execute();
    $sel->store_result();

    if ($sel->num_rows > 0) {
        $sel->bind_result($oldTitle, $oldDesc);
        $sel->fetch();
        $sel->close();

        // — función para normalizar texto —
        // — función global para normalizar texto — 
        if (! function_exists('normalizeText')) {
            function normalizeText(string $txt): string
            {
                // decodifica entidades HTML
                $t = html_entity_decode($txt, ENT_QUOTES, 'UTF-8');
                // quita etiquetas HTML
                $t = strip_tags($t);
                // unifica saltos de línea a "\n"
                $t = preg_replace('/\R+/', "\n", $t);
                // reemplaza múltiples espacios/tabulaciones por uno solo
                $t = trim(preg_replace('/[ \t]+/', ' ', $t));
                // pasa a minúsculas
                return mb_strtolower($t, 'UTF-8');
            }
        }

        // — normalizar títulos y descripciones —
        $oldTitleNorm = normalizeText($oldTitle);
        $newTitleNorm = normalizeText($title);
        $oldDescNorm  = normalizeText($oldDesc);
        $newDescNorm  = normalizeText($description);

        // — comparar —
        $igual = ($oldTitleNorm === $newTitleNorm && $oldDescNorm === $newDescNorm)
            ? 1
            : 0;

        $upd   = $conn->prepare("
            UPDATE tb_marketplace_productos
               SET igualTituloDesc    = ?,
                   idCategoria         = ?,
                   costoAdicional      = ?,
                   porcentajeAdicional = ?,
                   precioActualMP      = ?,
                   stockActualMP       = ?,
                   vendidosMP          = ?,
                   idEstadoMP          = ?,
                   checkImport         = 1
             WHERE idMarketplace = 1
               AND refMP = ?
        ");
        $upd->bind_param(
            'isdddiiis',
            $igual,           // int
            $category_id,     // string
            $fixed_fee,       // double
            $percentage_fee,  // double
            $price,           // double
            $stock,           // int  ← antes usaba $category_id
            $sold_qty,        // int
            $idEstadoMP,      // int
            $id               // string
        );
        $upd->execute();
        $upd->close();
    } else {
        $sel->close();
        $log = $conn->prepare("
            INSERT INTO tb_marketplace_logs (idMarketplace, instancia, mensaje)
            VALUES (1, 'importación', ?)
        ");
        $msg = "El producto con ID {$id} no está sincronizado con Compranet";
        $log->bind_param('s', $msg);
        $log->execute();
        $log->close();
    }

    // 5.2) Variantes: validar existencia y coleccionar para bulk update
    foreach ($p['variations'] ?? [] as $v) {
        $varId  = $v['id'];
        $stock  = (int)   ($v['available_quantity'] ?? 0);
        $vprice = (float) ($v['price'] ?? 0.0);
        $color  = '';
        foreach ($v['attribute_combinations'] as $a) {
            if (($a['id'] ?? '') === 'COLOR') {
                $color = $a['value_name'] ?? '';
                break;
            }
        }

        $check = $conn->prepare("
            SELECT 1
              FROM tb_marketplace_variantes mv
              JOIN tb_marketplace_productos mp
                ON mv.idMarketplaceProducto = mp.id
               AND mp.idMarketplace = 1
             WHERE mv.refMPVariante = ?
        ");
        $check->bind_param('s', $varId);
        $check->execute();
        $check->store_result();

        if ($check->num_rows > 0) {
            // existe, preparar para bulk update
            $variantUpdates[] = [
                'ref'   => $varId,
                'stock' => $stock,
                'price' => $vprice,
                'color' => $color,
            ];
        } else {
            // no existe, log
            $logv = $conn->prepare("
                INSERT INTO tb_marketplace_logs (idMarketplace, instancia, mensaje)
                VALUES (1, 'importación', ?)
            ");
            $msgv = "La variación con ID {$varId} del producto {$id} no está sincronizada con Compranet";
            $logv->bind_param('s', $msgv);
            $logv->execute();
            $logv->close();
        }
        $check->close();
    }
}

// ▶️ Ejecutar sincronización
importacionSync($conn);
$conn->close();
