<?php
// crearvariacionesml.php — Script para crear variaciones en ML de productos ya publicados

require __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/config/db.php';  // Debe definir $conn = new mysqli(...)

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

const SITE_ID = 'MCO';

$http = new Client([
    'base_uri' => 'https://api.mercadolibre.com',
    'timeout'  => 30,
]);

function getCredentials(mysqli $conn): array
{
    $res = $conn->query("
        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
    ");
    if (!$row = $res->fetch_assoc()) {
        die("ERROR: Credenciales no disponibles. Ejecuta authorize.php primero.\n");
    }
    return [
        'user_id'       => $row['user_id'],
        'access_token'  => $row['access_token'],
        'refresh_token' => $row['refresh_token'],
        'expires_in'    => $row['expires_in'],
        'updated_at'    => $row['updated_at'],
    ];
}

function refreshTokenIfNeeded(Client $http, array &$creds, mysqli $conn)
{
    $expTs = strtotime($creds['updated_at']) + $creds['expires_in'];
    if (time() < $expTs - 60) {
        return;
    }
    $r = $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'],
    ]);
    $d = json_decode((string)$r->getBody(), true);
    foreach (['access_token', 'refresh_token', 'expires_in'] as $k) {
        $creds[$k] = $d[$k];
    }
    $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();
}

/**
 * request con retry para 429 y 503
 */
function updateWithRetry(Client $http, string $method, string $endpoint, string $token, array $payload = [], int $retries = 3)
{
    $attempt = 0;
    while (true) {
        try {
            usleep(100000);
            $opts = [
                'headers' => [
                    'Authorization' => "Bearer {$token}",
                    'Content-Type'  => 'application/json'
                ],
            ];
            if ($method !== 'GET') {
                $opts['json'] = $payload;
            }
            $resp = match ($method) {
                'GET'  => $http->get($endpoint, $opts),
                'POST' => $http->post($endpoint, $opts),
                default => $http->put($endpoint, $opts),
            };
            return json_decode((string)$resp->getBody(), true);
        } catch (RequestException $ex) {
            $code = $ex->getResponse()?->getStatusCode() ?: 0;
            if (($code === 429 || $code === 503) && $attempt++ < $retries) {
                // retry on rate-limit or service unavailable
                sleep((int)$ex->getResponse()->getHeaderLine('Retry-After') ?: 5);
                continue;
            }
            throw $ex;
        }
    }
}

function uploadPicture(Client $http, string $token, string $url): ?string
{
    try {
        $r = $http->post('/pictures', [
            'headers' => [
                'Authorization' => "Bearer {$token}",
                'Content-Type'  => 'application/json'
            ],
            'json' => ['source' => $url],
        ]);
        $d = json_decode((string)$r->getBody(), true);
        return $d['id'] ?? null;
    } catch (RequestException $ex) {
        return null;
    }
}

// — Inicio del script —

$creds = getCredentials($conn);
refreshTokenIfNeeded($http, $creds, $conn);
$token = $creds['access_token'];

// 1) Borrar logs anteriores
$conn->query("
    DELETE FROM tb_marketplace_logs
     WHERE instancia='variacion' AND idMarketplace=1
");

// 2) Consulta variantes pendientes
$sql = <<<SQL
SELECT
  v.idVariante,
  v.skuMPVariante,
  v.stockPublicacion,
  v.colorTipoVariante,
  p.refMP,
  iv.linkImagen,
  v.precioPublicacion
FROM tb_marketplace_productos p
JOIN tb_marketplace_variantes v
  ON p.id = v.idMarketplaceProducto
JOIN tb_imagenes_variantes iv
  ON v.idVariante = iv.idVariante
WHERE v.stockPublicacion > 0
  AND (v.refMPVariante IS NULL OR v.refMPVariante = '')
  AND v.conectado = 0
  AND p.refMP > '0'
ORDER BY v.skuMPVariante
SQL;

$res = $conn->query($sql);
if ($conn->error) {
    die("Error en consulta: {$conn->error}\n");
}

while ($row = $res->fetch_assoc()) {
    $localId = $row['idVariante'];
    $itemId  = $row['refMP'];
    $sku     = $row['skuMPVariante'];
    $stock   = (int)$row['stockPublicacion'];
    $color   = $row['colorTipoVariante'];
    $urlImg  = str_replace('J:/', 'https://sistema.compranet.com.co/', $row['linkImagen']);
    $price   = (float)$row['precioPublicacion'];

    // subir al pool global
    $picId = uploadPicture($http, $token, $urlImg);

    // asociar al ítem—intentamos aunque falle
    if ($picId) {
        try {
            updateWithRetry(
                $http,
                'POST',
                "/items/{$itemId}/pictures",
                $token,
                ['id' => $picId]
            );
        } catch (RequestException $ignore) {
            // si falla, seguimos de todas formas
        }
    }

    // armar payload
    $payload = [
        'seller_custom_field'    => $sku,
        'price'                  => $price,
        'available_quantity'     => $stock,
        'attribute_combinations' => [
            ['id' => 'COLOR', 'value_name' => $color],
        ],
        'attributes' => [
            ['id' => 'SELLER_SKU', 'value_name' => $sku],
        ],
    ];
    if ($picId) {
        $payload['picture_ids'] = [$picId];
    }

    try {
        $resp = updateWithRetry(
            $http,
            'POST',
            "/items/{$itemId}/variations",
            $token,
            $payload
        );

        // obtener ID
        // obtener ID (puede venir como objeto con 'id' o como array de ids)
        // obtener ID (y si no, dump y excepción detallada)
        // obtener ID (objeto con 'id' o array de objetos con 'id')
        $newId = null;
        if (isset($resp['id'])) {
            // caso { "id": 12345 }
            $newId = $resp['id'];
        } elseif (
            is_array($resp)
            && isset($resp[0]['id'])
        ) {
            // caso [{ "id": 12345 }, …]
            $newId = $resp[0]['id'];
        }

        if (!$newId) {
            // volcar la respuesta a error_log para depurar
            error_log("RESPUESTA VARIACIÓN sin ID para SKU {$sku}: " . print_r($resp, true));
            throw new Exception("No devolvió ID para variación SKU {$sku}");
        }



        // actualizar local
        $up = $conn->prepare("
            UPDATE tb_marketplace_variantes
               SET refMPVariante=?, conectado=1
             WHERE idVariante=?
        ");
        $up->bind_param('si', $newId, $localId);
        $up->execute();
        $up->close();
    } catch (\Throwable $ex) {
        $body = $ex instanceof RequestException
            && $ex->getResponse()
            ? (string)$ex->getResponse()->getBody()
            : $ex->getMessage();

        // duplicado de atributo o fotos vs lista: fallback por SKU
        if (
            str_contains($body, 'Variation attribute is duplicated')
            || str_contains($body, 'not present in item pictures list')
        ) {
            try {
                $itemData = updateWithRetry(
                    $http,
                    'GET',
                    "/items/{$itemId}",
                    $token,
                    [],
                    3
                );
                $newId = null;
                foreach ($itemData['variations'] ?? [] as $v) {
                    if (($v['seller_custom_field'] ?? '') === $sku) {
                        $newId = $v['id'];
                        break;
                    }
                }
                if ($newId) {
                    $up = $conn->prepare("
                        UPDATE tb_marketplace_variantes
                           SET refMPVariante=?, conectado=1
                         WHERE idVariante=?
                    ");
                    $up->bind_param('si', $newId, $localId);
                    $up->execute();
                    $up->close();
                    continue;
                }
            } catch (\Throwable $_) {
                // si falla el fallback, caemos al log
            }
        }

        // log error
        $err = json_decode($body, true) ?: [];
        $details = [];
        foreach ($err['cause'] ?? [] as $c) {
            $details[] = $c['message'] ?? ($c['field'] ?? json_encode($c));
        }
        $detailText = $details
            ? implode('; ', $details)
            : ($err['message'] ?? $body);

        $msg = sprintf(
            "No se pudo crear la variación para el producto %s: %s",
            $itemId,
            $detailText
        );
        $log = $conn->prepare("
            INSERT INTO tb_marketplace_logs(instancia,mensaje,idMarketplace)
            VALUES('variacion',?,1)
        ");
        $log->bind_param('s', $msg);
        $log->execute();
        $log->close();
    }
}

echo "Proceso de creación de variaciones completado.\n";
