<?php

namespace Tests\Unit\Storage;

use Tests\Support\Storage\StorageTestCase;

/**
 * Optional live S3 integration tests.
 *
 * Runs only when .env (or environment) has:
 * FILE_STORAGE_DRIVER=s3, AWS_BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
 *
 * @internal
 * @group s3-integration
 */
final class S3StorageIntegrationTest extends StorageTestCase
{
    private ?string $uploadedPolicyKey = null;

    private ?string $uploadedEndorsementKey = null;

    protected function tearDown(): void
    {
        if ($this->s3IntegrationEnabled()) {
            $this->useS3DriverFromEnv();

            if ($this->uploadedPolicyKey !== null) {
                @storage()->deleteKey($this->uploadedPolicyKey);
            }

            if ($this->uploadedEndorsementKey !== null) {
                @storage()->deleteKey($this->uploadedEndorsementKey);
            }
        }

        parent::tearDown();
    }

    public function testS3DriverIsActiveFromEnv(): void
    {
        $this->skipUnlessS3Integration();

        $this->assertTrue(storage()->isS3());
    }

    public function testS3PolicyPdfUploadExistsReadAndDelete(): void
    {
        $this->skipUnlessS3Integration();

        $fileName = 'test_policy_' . uniqid('', true) . '.pdf';
        $file     = $this->createUploadedFile('%PDF-1.4 test policy', $fileName, 'application/pdf');

        $stored = policy_upload_pdf($file);

        $this->assertIsString($stored);
        $this->assertNotSame('', $stored);
        $this->uploadedPolicyKey = storage()->resolveKey('policy', 'policy_pdf', $stored);
        $this->assertTrue(policy_exists_by_type($stored, 'policy_pdf'));
        $this->assertSame('%PDF-1.4 test policy', storage_read('policy', 'policy_pdf', $stored));

        $tempPath = policy_local_pdf_path($stored);
        $this->assertFileExists($tempPath);
        storage_cleanup_temp($tempPath);
        $this->assertFileDoesNotExist($tempPath);

        $this->assertTrue(storage_delete('policy', 'policy_pdf', $stored));
        $this->uploadedPolicyKey = null;
        $this->assertFalse(policy_exists_by_type($stored, 'policy_pdf'));
    }

    public function testS3PolicyReceiptUploadAndTemporaryUrl(): void
    {
        $this->skipUnlessS3Integration();

        $fileName = 'test_receipt_' . uniqid('', true) . '.jpg';
        $file     = $this->createUploadedFile('receipt-image-bytes', $fileName, 'image/jpeg');

        $stored = policy_upload_receipt($file);

        $this->assertIsString($stored);
        $this->assertNotSame('', $stored);
        $this->uploadedPolicyKey = storage()->resolveKey('policy', 'policy_payment_receipt', $stored);
        $this->assertTrue(policy_exists_by_type($stored, 'policy_payment_receipt'));

        $url = storage_temporary_url('policy', 'policy_payment_receipt', $stored);
        $this->assertStringStartsWith('https://', $url);
    }

    public function testS3PolicyMarkdownPutAndRead(): void
    {
        $this->skipUnlessS3Integration();

        $mdName  = 'test_' . uniqid('', true) . '.md';
        $content = str_repeat('policy markdown ', 40);

        policy_put_md($mdName, $content);
        $this->uploadedPolicyKey = storage()->resolveKey('policy', 'policy_md', $mdName);

        $this->assertTrue(policy_md_exists($mdName));
        $this->assertSame($content, policy_read_md($mdName));
    }

    public function testS3EndorsementOriginalAndCompletionUpload(): void
    {
        $this->skipUnlessS3Integration();

        $originalFile = $this->createUploadedFile('original', 'orig.pdf', 'application/pdf');
        $completionFile = $this->createUploadedFile('completion', 'comp.pdf', 'application/pdf');

        $original   = endorsement_upload_original($originalFile);
        $completion = endorsement_upload_completion($completionFile);

        $this->assertIsString($original);
        $this->assertIsString($completion);
        $this->uploadedEndorsementKey = storage()->resolveKey('endorsement', '', $original);
        $this->assertTrue(endorsement_exists_by_type($original, 'original'));
        $this->assertTrue(endorsement_exists_by_type($completion, 'completion'));

        $response = endorsement_download_by_type($completion, 'completion', true);
        $this->assertStringContainsString('inline', $response->getHeaderLine('Content-Disposition'));
    }

    public function testLocalDriverScenarioStillWorksWhenEnvIsLocal(): void
    {
        if (getenv('FILE_STORAGE_DRIVER') === 's3') {
            $this->markTestSkipped('This scenario validates explicit local override; current env is s3.');
        }

        $this->useLocalDriver();

        $stored = policy_upload_pdf(
            $this->createUploadedFile('local pdf', 'local.pdf', 'application/pdf')
        );

        $this->assertNotNull($stored);
        $this->assertTrue(policy_exists_by_type($stored, 'policy_pdf'));
        $this->assertFileExists($this->localFilePath(storage()->resolveKey('policy', 'policy_pdf', $stored)));
    }
}

/**
 * @internal
 */
final class StorageScenarioMatrixTest extends StorageTestCase
{
    public function testAllPolicyFoldersCanStoreAndRetrieve(): void
    {
        $scenarios = [
            ['policy_pdf', 'policy.pdf', 'pdf-content'],
            ['policy_payment_receipt', 'receipt.jpg', 'receipt-content'],
            ['policy_md', 'policy.md', str_repeat('md ', 200)],
        ];

        foreach ($scenarios as [$folder, $name, $contents]) {
            storage_put('policy', $folder, $name, $contents);

            $this->assertTrue(storage_exists('policy', $folder, $name), "Missing {$folder}/{$name}");
            $this->assertSame($contents, storage_read('policy', $folder, $name), "Read failed {$folder}/{$name}");
        }
    }

    public function testAllEndorsementFoldersCanStoreAndRetrieve(): void
    {
        storage_put('endorsement', '', 'original.pdf', 'original');
        storage_put('endorsement', 'endorsement_pdf', 'completion.pdf', 'completion');

        $this->assertSame('original', storage_read('endorsement', '', 'original.pdf'));
        $this->assertSame('completion', storage_read('endorsement', 'endorsement_pdf', 'completion.pdf'));
    }

    public function testMissingFileDownloadScenarioThrowsOrFailsExistsCheck(): void
    {
        $this->assertFalse(policy_exists_by_type('missing.pdf', 'policy_pdf'));
        $this->assertFalse(endorsement_exists_by_type('missing.pdf', 'original'));
        $this->assertFalse(endorsement_exists_by_type('missing.pdf', 'completion'));
    }

    public function testReplaceEndorsementCompletionDeletesOldFile(): void
    {
        $oldName = endorsement_upload_completion(
            $this->createUploadedFile('old completion', 'old.pdf', 'application/pdf')
        );
        $this->assertTrue(endorsement_exists_by_type($oldName, 'completion'));

        endorsement_delete_completion($oldName);
        $this->assertFalse(endorsement_exists_by_type($oldName, 'completion'));

        $newName = endorsement_upload_completion(
            $this->createUploadedFile('new completion', 'new.pdf', 'application/pdf')
        );
        $this->assertTrue(endorsement_exists_by_type($newName, 'completion'));
    }
}
