<?php
declare(strict_types=1);

final class MediaUpload
{
    public const MAX_IMAGE_BYTES = 8_000_000;
    public const MAX_VIDEO_BYTES = 80_000_000;

    /**
     * @return array{ok:bool, path?:string, error?:string}
     */
    public static function productImage(array $file): array
    {
        return self::handle($file, 'products', ['image/jpeg', 'image/png', 'image/webp'], self::MAX_IMAGE_BYTES, ['jpg', 'jpeg', 'png', 'webp']);
    }

    /**
     * @return array{ok:bool, path?:string, error?:string}
     */
    public static function productVideo(array $file): array
    {
        return self::handle($file, 'products', ['video/mp4', 'video/webm'], self::MAX_VIDEO_BYTES, ['mp4', 'webm']);
    }

    /**
     * @return array{ok:bool, path?:string, error?:string}
     */
    public static function profileImage(array $file): array
    {
        return self::handle($file, 'profiles', ['image/jpeg', 'image/png', 'image/webp'], self::MAX_IMAGE_BYTES, ['jpg', 'jpeg', 'png', 'webp']);
    }

    /**
     * @param list<string> $mimeWhitelist
     * @param list<string> $extWhitelist
     * @return array{ok:bool, path?:string, error?:string}
     */
    private static function handle(array $file, string $subdir, array $mimeWhitelist, int $maxBytes, array $extWhitelist): array
    {
        if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
            return ['ok' => false, 'error' => 'no_file'];
        }
        if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) {
            return ['ok' => false, 'error' => 'upload_error'];
        }
        $size = (int)($file['size'] ?? 0);
        if ($size <= 0 || $size > $maxBytes) {
            return ['ok' => false, 'error' => 'size'];
        }
        $tmp = (string)$file['tmp_name'];
        if (!is_uploaded_file($tmp)) {
            return ['ok' => false, 'error' => 'invalid'];
        }
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        $mime = $finfo->file($tmp) ?: '';
        if (!in_array($mime, $mimeWhitelist, true)) {
            return ['ok' => false, 'error' => 'mime'];
        }
        $ext = strtolower(pathinfo((string)$file['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, $extWhitelist, true)) {
            return ['ok' => false, 'error' => 'ext'];
        }

        $baseDir = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . $subdir;
        if (!is_dir($baseDir) && !mkdir($baseDir, 0775, true) && !is_dir($baseDir)) {
            return ['ok' => false, 'error' => 'mkdir'];
        }

        $safe = bin2hex(random_bytes(12)) . '.' . $ext;
        $dest = $baseDir . DIRECTORY_SEPARATOR . $safe;
        if (!move_uploaded_file($tmp, $dest)) {
            return ['ok' => false, 'error' => 'move'];
        }

        $public = 'storage/uploads/' . $subdir . '/' . $safe;
        return ['ok' => true, 'path' => str_replace('\\', '/', $public)];
    }

    public static function deletePublicPath(?string $relative): void
    {
        if ($relative === null || $relative === '') {
            return;
        }
        $relative = ltrim(str_replace(['..', '\\'], ['', '/'], $relative), '/');
        $full = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relative);
        if (is_file($full)) {
            @unlink($full);
        }
    }
}
