<?php

/**
 * Torob API v3 smoke tests (no live Torob JWT required).
 *
 * Run: php engine/tests/torob_api_smoke_test.php
 */

require __DIR__ . '/../vendor/autoload.php';

$app = require __DIR__ . '/../bootstrap/app.php';
$app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();

use App\Http\Controllers\Api\TorobApiController;
use App\Http\Middleware\VerifyTorobJwt;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\Setting;
use App\Services\TorobCatalogService;
use Illuminate\Http\Request;

$passed = 0;
$failed = 0;

function assert_true(bool $cond, string $label): void
{
    global $passed, $failed;
    if ($cond) {
        echo "  PASS  {$label}\n";
        $passed++;
    } else {
        echo "  FAIL  {$label}\n";
        $failed++;
    }
}

echo "=== Torob API v3 smoke tests ===\n\n";

// ── JWT helpers ──────────────────────────────────────────────────────────────
echo "-- JWT key seed --\n";
$mw = new VerifyTorobJwt();
$seed = $mw->publicKeySeed();
assert_true(strlen(base64_decode($seed, true) ?: '') === 32, 'public key seed is 32 bytes');

// Isolate host-derived aud from any admin override stored in settings
$prevAudience = Setting::get('torob_api_audience', '');
Setting::set('torob_api_audience', '');

$req = Request::create('https://example.com:8080/torob_api/v3/products', 'POST');
$req->headers->set('HOST', 'example.com:8080');
assert_true($mw->expectedAudience($req) === 'example.com:8080', 'audience includes non-default port');

$req80 = Request::create('http://shop.test/torob_api/v3/products', 'POST');
$req80->headers->set('HOST', 'shop.test');
assert_true($mw->expectedAudience($req80) === 'shop.test', 'audience is host without :80');

Setting::set('torob_api_audience', $prevAudience);

// ── Controller validation ────────────────────────────────────────────────────
echo "\n-- Request validation --\n";
$controller = app(TorobApiController::class);

function callProducts(TorobApiController $c, array $body): array
{
    $req = Request::create('/torob_api/v3/products', 'POST', [], [], [], [
        'CONTENT_TYPE' => 'application/json',
    ], json_encode($body, JSON_UNESCAPED_UNICODE));
    $req->headers->set('Accept', 'application/json');
    // Force JSON bag
    $req->server->set('HTTP_CONTENT_TYPE', 'application/json');
    $ref = new ReflectionClass($req);
    // Use Request::create with content — json() reads php://input; for tests use replace + merge
    $jsonReq = Request::create('/torob_api/v3/products', 'POST', [], [], [], [
        'CONTENT_TYPE' => 'application/json',
        'HTTP_ACCEPT'  => 'application/json',
    ], json_encode($body));
    // Laravel Request::json() uses decoded content from getContent()
    $response = $c->products($jsonReq);

    return [$response->getStatusCode(), $response->getData(true)];
}

[$code, $data] = callProducts($controller, []);
assert_true($code === 400 && isset($data['error']), 'empty body → 400 error');

[$code, $data] = callProducts($controller, ['page' => 1]);
assert_true($code === 400 && str_contains($data['error'] ?? '', 'sort'), 'page without sort → 400');

[$code, $data] = callProducts($controller, ['sort' => 'date_added_desc']);
assert_true($code === 400 && str_contains($data['error'] ?? '', 'page'), 'sort without page → 400');

[$code, $data] = callProducts($controller, ['page' => 1, 'sort' => 'invalid']);
assert_true($code === 400, 'invalid sort → 400');

[$code, $data] = callProducts($controller, ['page_urls' => []]);
assert_true($code === 400, 'empty page_urls → 400');

[$code, $data] = callProducts($controller, ['page' => 1, 'sort' => 'date_added_desc', 'page_urls' => ['x']]);
assert_true($code === 400, 'mixed modes → 400');

// ── Catalog shape (if DB has products) ───────────────────────────────────────
echo "\n-- Catalog mapping --\n";
$svc = app(TorobCatalogService::class);
$variant = ProductVariant::query()
    ->where('is_active', true)
    ->whereHas('product', fn ($q) => $q->where('is_active', true))
    ->with(['product.categories', 'product.images', 'product.attributes'])
    ->first();

if ($variant) {
    $mapped = $svc->mapVariant($variant);
    assert_true($mapped['page_unique'] === $variant->product_id . '_' . $variant->id, 'page_unique format');
    assert_true(str_starts_with($mapped['page_url'], 'http'), 'page_url is absolute');
    assert_true(str_contains($mapped['page_url'], 'v=' . $variant->id), 'page_url includes v=');
    assert_true(is_int($mapped['current_price']), 'current_price is int (Toman)');
    if ($mapped['availability']) {
        $expected = $variant->discount_price !== null
            && (float) $variant->discount_price > 0
            && (float) $variant->discount_price < (float) $variant->price
            ? (int) round((float) $variant->discount_price)
            : (int) round((float) $variant->price);
        assert_true($mapped['current_price'] === $expected, 'current_price is Toman (not Rial)');
    } else {
        assert_true($mapped['current_price'] === 0, 'unavailable → current_price 0');
    }
    assert_true(is_bool($mapped['availability']), 'availability is bool');
    assert_true(is_array($mapped['image_links']), 'image_links is list');
    assert_true(preg_match('/^\d{4}-\d{2}-\d{2}T/', $mapped['date_added']) === 1, 'date_added iso8601');
    assert_true(isset($mapped['date_updated']), 'date_updated present');
    assert_true(str_starts_with($mapped['page_url'], 'https://'), 'page_url is https');
    assert_true(is_object($mapped['spec']), 'spec is object (JSON dictionary, not array)');
    $encoded = json_encode(['spec' => $mapped['spec']], JSON_UNESCAPED_UNICODE);
    assert_true(str_contains($encoded, '"spec":{'), 'spec JSON-encodes as {}');

    $page = $svc->paginate(1, 'date_added_desc');
    assert_true($page['api_version'] === 'torob_api_v3', 'api_version');
    assert_true($page['current_page'] === 1, 'current_page');
    assert_true(is_int($page['total']) && is_int($page['max_pages']), 'total/max_pages ints');
    assert_true(count($page['products']) <= TorobCatalogService::PER_PAGE, 'page size ≤ 100');

    $missing = $svc->byUniques(['99999999_99999999']);
    assert_true($missing['total'] === 0 && $missing['products'] === [], 'missing unique → empty list');

    $hit = $svc->byUniques([$mapped['page_unique']]);
    assert_true($hit['total'] === 1 && ($hit['products'][0]['page_unique'] ?? null) === $mapped['page_unique'], 'unique lookup hit');

    $byUrl = $svc->byUrls([$mapped['page_url']]);
    assert_true($byUrl['total'] === 1, 'url lookup hit');
} else {
    echo "  SKIP  no active variants in DB — mapping tests skipped\n";
}

// ── Setting gate ─────────────────────────────────────────────────────────────
echo "\n-- Enable flag --\n";
$prev = Setting::get('torob_api_enabled', '0');
Setting::set('torob_api_enabled', '0');
$req = Request::create('/torob_api/v3/products', 'POST');
$resp = $mw->handle($req, fn () => response('ok'));
assert_true($resp->getStatusCode() === 503, 'disabled API → 503');
Setting::set('torob_api_enabled', $prev);

echo "\n=== Result: {$passed} passed, {$failed} failed ===\n";
exit($failed > 0 ? 1 : 0);
