<?php

declare(strict_types=1);

/**
 * Verifica offline del flusso OAuth per credential version.
 *
 * La prima richiesta in uscita e' sempre quella del token: la ispezioniamo per
 * asserire endpoint, Content-Type e scope corretti per ciascuna versione.
 *
 * Contratto confermato da tre fonti indipendenti (SDK di data-layer, client di
 * gclid-mapper, indicazioni dirette):
 *   - 2.x: Cognito, form-urlencoded, scope `creatorsapi/default`
 *   - 3.x: Login with Amazon, JSON, scope `creatorsapi::default`
 */

function tokenRequestFor(string $version, ?array &$history = null): \Psr\Http\Message\RequestInterface
{
    $client = mockedCreatorsClient(
        [jsonStubResponse(200, ['reports' => []])],
        $history,
        ['credentialVersion' => $version]
    );

    // Una qualsiasi operazione innesca il fetch del token (prima richiesta).
    $client->listReports();

    return $history[0]['request'];
}

dataset('cognitoVersions', [
    '2.1 NA' => ['2.1', 'https://creatorsapi.auth.us-east-1.amazoncognito.com/oauth2/token'],
    '2.2 EU' => ['2.2', 'https://creatorsapi.auth.eu-south-2.amazoncognito.com/oauth2/token'],
    '2.3 FE' => ['2.3', 'https://creatorsapi.auth.us-west-2.amazoncognito.com/oauth2/token'],
]);

dataset('lwaVersions', [
    '3.1 NA' => ['3.1', 'https://api.amazon.com/auth/o2/token'],
    '3.2 EU' => ['3.2', 'https://api.amazon.co.uk/auth/o2/token'],
    '3.3 FE' => ['3.3', 'https://api.amazon.co.jp/auth/o2/token'],
]);

test('le versioni 2.x usano Cognito, form-urlencoded e scope con slash', function (string $version, string $endpoint) {
    $request = tokenRequestFor($version);

    expect((string) $request->getUri())->toBe($endpoint);
    expect($request->getHeaderLine('Content-Type'))->toContain('application/x-www-form-urlencoded');

    parse_str((string) $request->getBody(), $params);
    expect($params['grant_type'])->toBe('client_credentials');
    expect($params['scope'])->toBe('creatorsapi/default');
})->with('cognitoVersions')->group('unit');

test('le versioni 3.x usano LwA, body JSON e scope con doppio due-punti', function (string $version, string $endpoint) {
    $request = tokenRequestFor($version);

    expect((string) $request->getUri())->toBe($endpoint);
    expect($request->getHeaderLine('Content-Type'))->toContain('application/json');

    $params = json_decode((string) $request->getBody(), true);
    expect($params['grant_type'])->toBe('client_credentials');
    expect($params['scope'])->toBe('creatorsapi::default');
})->with('lwaVersions')->group('unit');

test('una credential version sconosciuta viene rifiutata', function () {
    $client = mockedCreatorsClient([], $history, ['credentialVersion' => '9.9']);

    expect(fn () => $client->listReports())
        ->toThrow(InvalidArgumentException::class);
})->group('unit');

test('la 3.2 e le altre 3.x sono trattate come Login with Amazon', function () {
    // Contro-verifica esplicita del caso d'uso richiesto (v3.2 EU).
    $request = tokenRequestFor('3.2');

    expect((string) $request->getUri())->toBe('https://api.amazon.co.uk/auth/o2/token');
    expect($request->getHeaderLine('Content-Type'))->toContain('application/json');
})->group('unit');

/*
 * Header Authorization delle chiamate API (non del token).
 *
 * Il suffisso `, Version <x.y>` vale solo per le credenziali 2.x: la doc
 * ufficiale (concepts/common-request-headers-and-parameters) prescrive per le
 * 3.x il solo `Bearer <access_token>`. Vanno coperti entrambi i punti in cui il
 * client costruisce la richiesta: requestJson (feed/report) e getItems.
 */

test('le chiamate API con credenziali 2.x portano il suffisso Version', function (string $version) {
    $client = mockedCreatorsClient([jsonStubResponse(200, ['reports' => []])], $history, [
        'credentialVersion' => $version,
    ]);
    $client->listReports();

    expect(lastMockRequest($history)->getHeaderLine('Authorization'))
        ->toBe(sprintf('Bearer stub-access-token, Version %s', $version));
})->with(['2.1', '2.2', '2.3'])->group('unit');

test('le chiamate API con credenziali 3.x non portano il suffisso Version', function (string $version) {
    $client = mockedCreatorsClient([jsonStubResponse(200, ['reports' => []])], $history, [
        'credentialVersion' => $version,
    ]);
    $client->listReports();

    expect(lastMockRequest($history)->getHeaderLine('Authorization'))
        ->toBe('Bearer stub-access-token');
})->with(['3.1', '3.2', '3.3'])->group('unit');

test('anche getItems rispetta il contratto Authorization per versione', function (string $version, string $expected) {
    $client = mockedCreatorsClient([jsonStubResponse(200, ['itemsResult' => ['items' => []]])], $history, [
        'credentialVersion' => $version,
    ]);
    $client->getItems(['B0FJ8X2CL4']);

    expect(lastMockRequest($history)->getHeaderLine('Authorization'))->toBe($expected);
})->with([
    '2.2 EU con Version' => ['2.2', 'Bearer stub-access-token, Version 2.2'],
    '3.2 EU senza Version' => ['3.2', 'Bearer stub-access-token'],
])->group('unit');
