<?php

use App\Libraries\TemporaryImageUpload;
use CodeIgniter\Test\CIUnitTestCase;

/**
 * @internal
 */
final class TemporaryImageUploadTest extends CIUnitTestCase
{
    private string $workingPath;
    private string $temporaryPath;
    private string $destinationPath;

    protected function setUp(): void
    {
        parent::setUp();

        $this->workingPath = WRITEPATH . 'tests/temp-upload-' . bin2hex(random_bytes(5));
        $this->temporaryPath = $this->workingPath . '/temp';
        $this->destinationPath = $this->workingPath . '/destination';

        mkdir($this->temporaryPath, 0775, true);
    }

    protected function tearDown(): void
    {
        $this->removeDirectory($this->workingPath);

        parent::tearDown();
    }

    public function testMovesValidTemporaryFileToPermanentDirectory(): void
    {
        $token = str_repeat('a', 32) . '.png';
        file_put_contents($this->temporaryPath . '/' . $token, 'image-content');

        $upload = new TemporaryImageUpload($this->temporaryPath);
        $storedFile = $upload->moveToPermanent($token, $this->destinationPath, ['png']);

        $this->assertSame($token, $storedFile);
        $this->assertFileDoesNotExist($this->temporaryPath . '/' . $token);
        $this->assertFileExists($this->destinationPath . '/' . $token);
    }

    public function testRejectsUnknownTemporaryToken(): void
    {
        $upload = new TemporaryImageUpload($this->temporaryPath);

        $this->expectException(\RuntimeException::class);
        $upload->moveToPermanent('../invalid.png', $this->destinationPath, ['png']);
    }

    public function testCleanupRemovesOnlyFilesOlderThanMaximumAge(): void
    {
        $expired = $this->temporaryPath . '/' . str_repeat('b', 32) . '.png';
        $recent = $this->temporaryPath . '/' . str_repeat('c', 32) . '.png';
        file_put_contents($expired, 'expired');
        file_put_contents($recent, 'recent');
        touch($expired, time() - 7201);

        $upload = new TemporaryImageUpload($this->temporaryPath);
        $removed = $upload->cleanupExpired(7200);

        $this->assertSame(1, $removed);
        $this->assertFileDoesNotExist($expired);
        $this->assertFileExists($recent);
    }

    private function removeDirectory(string $directory): void
    {
        if (! is_dir($directory)) {
            return;
        }

        $files = scandir($directory);

        if ($files === false) {
            return;
        }

        foreach ($files as $fileName) {
            if ($fileName === '.' || $fileName === '..') {
                continue;
            }

            $filePath = $directory . '/' . $fileName;

            if (is_dir($filePath)) {
                $this->removeDirectory($filePath);
                continue;
            }

            unlink($filePath);
        }

        rmdir($directory);
    }
}
