<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\User\Import;

final readonly class ImportedClientFileStorage
{
    private const DIRECTORY = 'var/viti-core/imported-client-files';

    public function __construct(
        private string $kernelProjectDir,
    ) {}

    public function archive(string $sourcePath, string $extension): ImportedClientStoredFile
    {
        if (!is_file($sourcePath) || !is_readable($sourcePath)) {
            throw new \RuntimeException('The imported client source file is not readable.');
        }

        $directory = $this->directory();
        if (!is_dir($directory) && !mkdir($directory, 0o700, true) && !is_dir($directory)) {
            throw new \RuntimeException('The imported client archive directory cannot be created.');
        }

        $safeExtension = preg_replace('/[^a-z0-9]/', '', mb_strtolower($extension)) ?: 'bin';
        $filename = bin2hex(random_bytes(24)) . '.' . $safeExtension;
        $targetPath = $directory . DIRECTORY_SEPARATOR . $filename;

        if (!copy($sourcePath, $targetPath)) {
            throw new \RuntimeException('The imported client source file cannot be archived.');
        }

        @chmod($targetPath, 0o600);
        $size = filesize($targetPath);

        return new ImportedClientStoredFile($filename, false === $size ? 0 : $size);
    }

    public function path(string $filename): string
    {
        if ($filename !== basename($filename) || !preg_match('/^[a-f0-9]{48}\.[a-z0-9]+$/', $filename)) {
            throw new \InvalidArgumentException('Invalid imported client archive filename.');
        }

        return $this->directory() . DIRECTORY_SEPARATOR . $filename;
    }

    public function remove(string $filename): void
    {
        $path = $this->path($filename);
        if (is_file($path)) {
            @unlink($path);
        }
    }

    private function directory(): string
    {
        return $this->kernelProjectDir . DIRECTORY_SEPARATOR . self::DIRECTORY;
    }
}
