<?php

namespace App\Libraries;

use CodeIgniter\HTTP\Files\UploadedFile;
use RuntimeException;

class TemporaryImageUpload
{
    private string $temporaryPath;

    public function __construct(?string $temporaryPath = null)
    {
        $this->temporaryPath = $temporaryPath ?? WRITEPATH . 'uploads/temp';
    }

    public function store(UploadedFile $file, array $allowedExtensions): string
    {
        $extension = strtolower($file->getClientExtension());

        if (! in_array($extension, $allowedExtensions, true)) {
            throw new RuntimeException('Format file tidak didukung.');
        }

        $this->ensureDirectory($this->temporaryPath);

        $fileName = bin2hex(random_bytes(16)) . '.' . $extension;
        $file->move($this->temporaryPath, $fileName);

        return $fileName;
    }

    public function assertAvailable(?string $fileName, array $allowedExtensions): void
    {
        if ($fileName === null || trim($fileName) === '') {
            return;
        }

        $fileName = trim($fileName);
        $extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));

        if (
            basename($fileName) !== $fileName
            || ! preg_match('/\A[a-f0-9]{32}\.[a-z0-9]+\z/', $fileName)
            || ! in_array($extension, $allowedExtensions, true)
            || ! is_file($this->temporaryPath . DIRECTORY_SEPARATOR . $fileName)
        ) {
            throw new RuntimeException('File sementara tidak tersedia. Silakan upload ulang.');
        }
    }

    public function moveToPermanent(?string $fileName, string $destinationPath, array $allowedExtensions): ?string
    {
        if ($fileName === null || trim($fileName) === '') {
            return null;
        }

        $fileName = trim($fileName);
        $this->assertAvailable($fileName, $allowedExtensions);
        $this->ensureDirectory($destinationPath);

        $source = $this->temporaryPath . DIRECTORY_SEPARATOR . $fileName;
        $destination = $destinationPath . DIRECTORY_SEPARATOR . $fileName;

        if (! rename($source, $destination)) {
            throw new RuntimeException('Gagal menyimpan file. Silakan coba kembali.');
        }

        return $fileName;
    }

    public function cleanupExpired(int $maximumAgeSeconds = 7200): int
    {
        if (! is_dir($this->temporaryPath)) {
            return 0;
        }

        $removed = 0;
        $threshold = time() - $maximumAgeSeconds;
        $files = scandir($this->temporaryPath);

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

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

            $filePath = $this->temporaryPath . DIRECTORY_SEPARATOR . $fileName;

            if (is_file($filePath) && filemtime($filePath) <= $threshold && unlink($filePath)) {
                $removed++;
            }
        }

        return $removed;
    }

    private function ensureDirectory(string $directory): void
    {
        if (! is_dir($directory)) {
            mkdir($directory, 0775, true);
        }
    }
}
