<?php
session_start();
ob_start();

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';
const PREDICT_LIMIT     = 8;
const CATEGORY_FALLBACK = 'MCO12345';
const DEFAULT_BRAND     = 'Genérica';

$http = new Client([
    'base_uri' => 'https://api.mercadolibre.com',
    'timeout'  => 30,
]);

// — helpers for ML OAuth —
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("<p class='error'>ERROR: Ejecuta authorize.php primero.</p>");
    }
    return $row;
}

function refreshTokenIfNeeded(Client $http, array &$creds, mysqli $conn)
{
    $expiresAt = strtotime($creds['updated_at']) + $creds['expires_in'];
    if (time() < $expiresAt - 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((string)$resp->getBody(), true);
    file_put_contents(
        __DIR__ . '/ml_pictures.log',
        date('c') . " | REFRESH TOKEN response:\n" . print_r($data, true) . "\n",
        FILE_APPEND
    );

    $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 idMP = 1
    ");
    $u->bind_param(
        'ssi',
        $creds['access_token'],
        $creds['refresh_token'],
        $creds['expires_in']
    );
    $u->execute();
    $u->close();
}

function updateWithRetry(Client $http, string $method, string $endpoint, string $token, array $payload = [], int $maxRetries = 3)
{
    $attempt = 0;
    do {
        try {
            $opts = [
                'headers' => [
                    'Authorization' => "Bearer {$token}",
                    'Content-Type'  => 'application/json',
                    'Accept'        => 'application/json'
                ],
            ];
            if (in_array(strtoupper($method), ['POST', 'PUT', 'PATCH'])) {
                $opts['json'] = $payload;
            }
            $resp = match (strtoupper($method)) {
                'GET'  => $http->get($endpoint, $opts),
                'POST' => $http->post($endpoint, $opts),
                'PUT'  => $http->put($endpoint, $opts),
                default => throw new \InvalidArgumentException("Método inválido {$method}")
            };
            return json_decode((string)$resp->getBody(), true);
        } catch (RequestException $e) {
            $status = $e->getResponse()?->getStatusCode() ?: 0;
            if ($status === 429 && $attempt++ < $maxRetries) {
                sleep((int)($e->getResponse()->getHeaderLine('Retry-After') ?: 5));
                continue;
            }
            throw $e;
        }
    } while ($attempt <= $maxRetries);

    throw new \RuntimeException("Demasiados reintentos en {$endpoint}");
}


function uploadPicture(Client $http, string $token, string $url): ?string
{
    try {
        $r = $http->post('/pictures', [
            'headers' => [
                'Authorization' => "Bearer {$token}",
                'Content-Type' => 'application/json',
                'Accept' => 'application/json'
            ],
            'json' => ['source' => $url]
        ]);
        $d = json_decode((string)$r->getBody(), true);
        file_put_contents(
            __DIR__ . '/ml_pictures.log',
            date('c') . " | UPLOAD {$url} -> " . print_r($d, true) . "\n",
            FILE_APPEND
        );
        return $d['id'] ?? null;
    } catch (RequestException $e) {
        file_put_contents(
            __DIR__ . '/ml_pictures.log',
            date('c') . " | ERROR uploading {$url}: " . $e->getMessage() . "\n",
            FILE_APPEND
        );
        return null;
    }
}

function predictCategories(Client $http, string $token, string $query): array
{
    $r = $http->get("/sites/" . SITE_ID . "/domain_discovery/search", [
        'headers' => ['Authorization' => "Bearer {$token}", 'Accept' => 'application/json'],
        'query'   => ['limit' => PREDICT_LIMIT, 'q' => $query]
    ]);
    $data = json_decode((string)$r->getBody(), true);
    // devuelve hasta 3 IDs
    return array_column(array_slice($data, 0, 3), 'category_id');
}



// — Bulk publish UI buttons (same as wizard) —
if (isset($_GET['action'])) {
    if ($_GET['action'] === 'update_mp') {
        $conn->query("CALL actualizarTituloMarketplace()");
        header('Location: ' . $_SERVER['PHP_SELF']);
        exit;
    }
    if ($_GET['action'] === 'update_full_mp') {
        $conn->query("CALL actualizarMarketplace()");
        header('Location: ' . $_SERVER['PHP_SELF']);
        exit;
    }
}

// — Inicio Bulk Publish —
$creds = getCredentials($conn);
refreshTokenIfNeeded($http, $creds, $conn);
$token = $creds['access_token'];

// Buttons
echo '<div class="mb-3">
    <a href="?action=update_full_mp" class="btn btn-success">Actualización Completa MP</a>
    <a href="?action=update_mp" class="btn btn-success">Actualizar Título y Descripción</a>
</div>';

echo "<h1>Bulk Publish en MercadoLibre</h1><ul>";

// Query products to publish
$res = $conn->query("
    SELECT id, tituloPublicacion, descripcionPublicacion,
           precioPublicacion, stockPublicacion, skuMP, combo
      FROM tb_marketplace_productos
     WHERE idMarketplace=1 AND activo=1 AND refMP IS NULL
     ORDER BY tituloPublicacion ASC
");

while ($prod = $res->fetch_assoc()) {
    $pid   = (int)$prod['id'];
    $title = $prod['tituloPublicacion'];
    echo "<li>«{$title}»: ";

    // 1) Category
    // 1) Try up to 3 categories
    $categoryCandidates = predictCategories($http, $token, $title);
    // 1) Intentar publicar en hasta 3 categorías sugeridas
    $categoryId = null;
    $cands      = predictCategories($http, $token, $title);      // ya devuelve 3 IDs
    foreach ($cands as $cat) {
        try {
            // Validamos que acepte al menos category_id
            updateWithRetry($http, 'POST', '/items/validate', $token, ['category_id' => $cat], 1);
            $categoryId = $cat;
            break;
        } catch (\Exception $e) {
            // si falla, probamos la siguiente categoría
        }
    }
    if (! $categoryId) {
        echo "❌ No se pudo publicar en ninguna de las categorías sugeridas.</li>";
        continue;  // pasamos al siguiente producto
    }

    // 2) Fetch technical specs to detect variation_attribute
    try {
        $tech = updateWithRetry($http, 'GET', "/categories/{$categoryId}/technical_specs/input", $token, [], 1);
    } catch (RequestException) {
        echo "❌ No tech specs.</li>";
        continue;
    }
    // detect varAttrId
    // 2) detect varAttrId y aplica preferencia
    $varAttrId = null;
    // primero intenta cualquiera marcado como variation_attribute
    foreach ($tech['groups'] as $g) {
        foreach ($g['components'] as $c) {
            foreach ($c['attributes'] as $a) {
                if (!empty($a['tags']['variation_attribute'])) {
                    $varAttrId = $a['id'];
                    break 3;
                }
            }
        }
    }
    // si no encontró, fuerza la preferencia
    $preferred = ['COLOR', 'EXTERIOR_COLOR'];
    foreach ($preferred as $pref) {
        if (in_array($pref, array_column(iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($tech['groups'])), false), 'id'))) {
            $varAttrId = $pref;
            break;
        }
    }
    // como último recurso
    if (!$varAttrId) {
        $varAttrId = 'COLOR';
    }


    // 3) Fetch full attributes metadata and build topAttrs
    try {
        $meta = updateWithRetry($http, 'GET', "/categories/{$categoryId}/attributes", $token, [], 1);
    } catch (RequestException) {
        echo "❌ No attributes.</li>";
        continue;
    }
    $allowed = array_filter($meta, function ($a) {
        $t = $a['tags'] ?? [];
        foreach (['hidden', 'read_only'] as $x) {
            if (!empty($t[$x])) return false;
        }
        return !str_starts_with($a['id'], 'PACKAGE_');
    });

    $topAttrs = [];
    foreach ($allowed as $a) {
        $id = $a['id'];
        // BRAND
        if ($id === 'BRAND') {
            $topAttrs[] = ['id' => $id, 'value_name' => DEFAULT_BRAND];
        }
        // MODEL
        elseif ($id === 'MODEL') {
            $topAttrs[] = ['id' => $id, 'value_name' => $prod['skuMP']];
        }
        // INK_COLOR
        elseif ($id === 'INK_COLOR') {
            $topAttrs[] = ['id' => $id, 'value_name' => 'Negra'];
        }
        // SALE_FORMAT & UNITS_PER_PACK for combos
        elseif ($id === 'SALE_FORMAT' && (int)$prod['combo'] > 1) {
            $topAttrs[] = ['id' => $id, 'value_name' => 'Pack'];
        } elseif ($id === 'UNITS_PER_PACK' && (int)$prod['combo'] > 1) {
            $topAttrs[] = ['id' => $id, 'value_name' => (string)$prod['combo']];
        }
        // fixed single-value attrs
        elseif (!empty($a['tags']['fixed']) && count($a['values'] ?? []) === 1) {
            $only = $a['values'][0];
            $topAttrs[] = ['id' => $id, 'value_id' => $only['id']];
        }

        // SPORT_BOTTLE_CAPACITY: extrae “620ml” o “15 oz” del título/descr.
        elseif ($id === 'SPORT_BOTTLE_CAPACITY') {
            $text = $prod['tituloPublicacion'] . ' ' . $prod['descripcionPublicacion'];
            if (preg_match('/\b\d+\s?(?:ml|oz)\b/i', $text, $m)) {
                $topAttrs[] = ['id' => $id, 'value_name' => $m[0]];
            }
        }
    }

    // 4) Gather variations
    $vStmt = $conn->prepare("
        SELECT v.skuMPVariante, v.precioPublicacion, v.stockPublicacion,
               v.colorTipoVariante, iv.linkImagen
          FROM tb_marketplace_variantes v
          JOIN tb_imagenes_variantes iv ON v.idVariante=iv.idVariante
         WHERE v.idMarketplaceProducto=? AND v.stockPublicacion>0
    ");
    $vStmt->bind_param('i', $pid);
    $vStmt->execute();
    $vStmt->bind_result($skuVar, $priceVar, $stockVar, $colorVar, $imgVar);

    $varsPayload = [];
    while ($vStmt->fetch()) {
        $url = str_replace('J:/', 'https://sistema.compranet.com.co/', $imgVar);
        $picId = uploadPicture($http, $token, $url);
        $entry = [
            'seller_custom_field' => $skuVar,
            'price' => (float)$priceVar,
            'available_quantity' => (int)$stockVar,
            'attribute_combinations' => [
                ['id' => $varAttrId, 'value_name' => $colorVar]
            ],
            'attributes' => [
                ['id' => 'SELLER_SKU', 'value_name' => $skuVar]
            ],
        ];
        if ($picId) $entry['picture_ids'] = [$picId];
        $varsPayload[] = $entry;
    }
    $vStmt->close();

    // 5) Build payload with full sale_terms (3 terms)
    $payload = [
        'site_id' => SITE_ID,
        'title' => $title,
        'category_id' => $categoryId,
        'price' => (float)$prod['precioPublicacion'],
        'currency_id' => 'COP',
        'available_quantity' => (int)$prod['stockPublicacion'],
        'buying_mode' => 'buy_it_now',
        'listing_type_id' => 'gold_pro',
        'condition' => 'new',
        'seller_custom_field' => $prod['skuMP'],
        'accepts_mercadopago' => true,
        'shipping' => ['mode' => 'not_specified', 'local_pick_up' => false],
        'sale_terms' => [
            ['id' => 'WARRANTY_TYPE', 'value_id' => '2230280'],
            ['id' => 'WARRANTY_TIME', 'value_name' => '30 días'],
            ['id' => 'MANUFACTURING_TIME', 'value_name' => '3 días'],
        ],
        'attributes' => $topAttrs,
        'variations' => $varsPayload,
        'pictures' => [],  // parent gallery left empty as in wizard
    ];

    // 6) Publish
    try {
        $resp = updateWithRetry($http, 'POST', '/items', $token, $payload);
        if (empty($resp['id'])) throw new \Exception('No devolvió ID');
        $mlId = $resp['id'];

        // description
        updateWithRetry($http, 'PUT', "/items/{$mlId}/description", $token, [
            'plain_text' => $prod['descripcionPublicacion']
        ]);

        // map remote variant IDs back to local
        $itemData = updateWithRetry($http, 'GET', "/items/{$mlId}", $token, [], 1);
        foreach ($itemData['variations'] ?? [] as $var) {
            $remoteVarId = $var['id'];
            $localSku = $var['seller_custom_field'];
            $u2 = $conn->prepare("
                UPDATE tb_marketplace_variantes
                   SET refMPVariante=?
                 WHERE skuMPVariante=? AND idMarketplaceProducto=?
            ");
            $u2->bind_param('ssi', $remoteVarId, $localSku, $pid);
            $u2->execute();
            $u2->close();
        }

        // update product record
        $u = $conn->prepare("
            UPDATE tb_marketplace_productos
               SET refMP=?, fechaSincronizacion=NOW()
             WHERE id=?
        ");
        $u->bind_param('si', $mlId, $pid);
        $u->execute();
        $u->close();

        echo "✅ ID {$mlId}</li>";
    } catch (\Exception $e) {
        echo "❌ Error: " . htmlspecialchars($e->getMessage()) . "</li>";
    }
}

echo "</ul>";
ob_end_flush();
