<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Tests\Commerce\Catalog\Enrollment;

use CpCreation\VitiCore\Commerce\Catalog\Enrollment\Model\CatalogEnrollmentRequest;
use CpCreation\VitiCore\Commerce\Catalog\Enrollment\Model\CatalogEnrollmentStatus;
use PHPUnit\Framework\TestCase;

final class CatalogEnrollmentRequestTest extends TestCase
{
    private const string INSTANCE_ID = '7ad9e145-910f-4de4-9cec-5f832494adef';
    private const string FINGERPRINT = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

    public function testAnActivationSignalCanBePreparedAndRegistered(): void
    {
        $request = new CatalogEnrollmentRequest(new \DateTimeImmutable('2026-07-22T10:00:00+00:00'));

        self::assertFalse($request->isPrepared());

        $request->prepare(self::INSTANCE_ID, self::FINGERPRINT);
        $request->markQueued(new \DateTimeImmutable('2026-07-22T10:01:00+00:00'));
        $request->markRegistered(
            new \DateTimeImmutable('2026-07-22T10:01:01+00:00'),
            'source-42',
            'https://hub.example/webhooks/source-42',
            'active',
            ['instance_id' => self::INSTANCE_ID, 'status' => 'active'],
        );

        self::assertTrue($request->isPrepared());
        self::assertSame(self::FINGERPRINT, $request->getConfigurationFingerprint());
        self::assertSame(CatalogEnrollmentStatus::REGISTERED, $request->getStatus());
        self::assertSame(1, $request->getDeliveryAttempts());
        self::assertSame('source-42', $request->getSourceId());
        self::assertSame('active', $request->getHubStatus());
        self::assertNull($request->getLastError());
    }

    public function testRetryableThenPermanentFailureKeepsUsefulState(): void
    {
        $request = CatalogEnrollmentRequest::prepared(self::INSTANCE_ID, self::FINGERPRINT);
        $attemptedAt = new \DateTimeImmutable('2026-07-22T10:01:00+00:00');

        $request->markQueued($attemptedAt->modify('-1 second'));
        $request->markRetryableFailure($attemptedAt, 'HTTP 429');
        $request->markPermanentFailure($attemptedAt->modify('+1 minute'), 'HTTP 400', ['code' => 'invalid']);

        self::assertSame(CatalogEnrollmentStatus::FAILED_PERMANENT, $request->getStatus());
        self::assertSame(2, $request->getDeliveryAttempts());
        self::assertSame(['code' => 'invalid'], $request->getLastResponse());
        self::assertSame('HTTP 400', $request->getLastError());
    }

    public function testExhaustedRetryCycleReturnsToPendingForDurableRecovery(): void
    {
        $request = CatalogEnrollmentRequest::prepared(self::INSTANCE_ID, self::FINGERPRINT);
        $attemptedAt = new \DateTimeImmutable('2026-07-22T10:01:00+00:00');

        $request->markQueued($attemptedAt->modify('-1 second'));
        $request->markRetryableFailure($attemptedAt, 'network');
        $request->releaseAfterRetriesExhausted($attemptedAt->modify('+1 minute'), 'retry cycle exhausted');

        self::assertSame(CatalogEnrollmentStatus::PENDING, $request->getStatus());
        self::assertFalse($request->isDeliveryComplete());
        self::assertNull($request->getPermanentlyFailedAt());
        self::assertSame('retry cycle exhausted', $request->getLastError());
    }
}
