<?php
declare(strict_types=1);

namespace Core;

/**
 * Tiny file-upload helper. Stores files under <ROOT>/storage/uploads/<subdir>/
 * and returns the relative path (e.g. "fuel/123/COLLECT_20260623120015_a1b2.jpg")
 * that should be written to the DB.
 */
final class Upload
{
    private const ALLOWED_MIME = [
        'image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp',
        'image/heic' => 'heic', 'image/heif' => 'heif',
        'application/pdf' => 'pdf',
    ];

    /**
     * @param array $file  one entry of $_FILES (with tmp_name, type, size, error, name)
     * @param string $subdir e.g. "fuel/123"
     * @param string $prefix optional filename prefix
     * @return string relative path stored ("fuel/123/COLLECT_20260623120015_a1b2.jpg")
     */
    public static function save(array $file, string $subdir, string $prefix = ''): string
    {
        if (!is_array($file) || ($file['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
            throw new \RuntimeException('Upload failed: error code ' . ($file['error'] ?? 'unknown'));
        }
        $max = (int) env('UPLOAD_MAX_BYTES', 10 * 1024 * 1024);
        if (($file['size'] ?? 0) > $max) {
            throw new \RuntimeException('File too large');
        }
        if (!is_uploaded_file($file['tmp_name'])) {
            // Allow non-multipart in tests, but require an existing file
            if (!is_file($file['tmp_name'])) throw new \RuntimeException('No uploaded file');
        }

        $mime = self::detectMime($file['tmp_name'], $file['type'] ?? '');
        $ext  = self::ALLOWED_MIME[$mime] ?? null;
        if (!$ext) throw new \RuntimeException("Unsupported file type: {$mime}");

        $name = trim($prefix . '_' . date('YmdHis') . '_' . bin2hex(random_bytes(3)), '_') . '.' . $ext;
        $relDir = trim(str_replace('\\', '/', $subdir), '/');
        $relPath = $relDir . '/' . $name;

        $absDir = STORAGE . DS . 'uploads' . DS . str_replace('/', DS, $relDir);
        if (!is_dir($absDir) && !mkdir($absDir, 0775, true) && !is_dir($absDir)) {
            throw new \RuntimeException("Cannot create dir: {$absDir}");
        }
        $absPath = $absDir . DS . $name;

        if (!@move_uploaded_file($file['tmp_name'], $absPath)) {
            if (!@copy($file['tmp_name'], $absPath)) {
                throw new \RuntimeException("Cannot write file: {$absPath}");
            }
        }
        return $relPath;
    }

    private static function detectMime(string $tmpPath, string $declared): string
    {
        if (function_exists('finfo_open')) {
            $f = finfo_open(FILEINFO_MIME_TYPE);
            $m = finfo_file($f, $tmpPath);
            finfo_close($f);
            if ($m) return strtolower($m);
        }
        return strtolower($declared ?: 'application/octet-stream');
    }
}
