<?php

namespace App\Shared\Service;

use Symfony\Component\HttpFoundation\Request;

/**
 * Stores a raw-body file upload (the `/file/upload/...` convention: the file is
 * sent as the request body with a Content-Disposition filename) under
 * public/uploads/<subDir>/<year>-<month>/ and returns its public URL + metadata.
 */
class FileUploadService
{
    public function __construct(
        private readonly FileValidatorService $fileValidator,
        private readonly string $projectDir,
    ) {}

    /**
     * @return array{url: string, filename: string, filemime: string, size: int}
     * @throws \RuntimeException on an invalid/oversized file
     */
    public function storeFromRequest(Request $request, string $subDir): array
    {
        $content = $request->getContent();
        preg_match('/filename=["\']?([^"\';\s]+)["\']?/i', $request->headers->get('Content-Disposition', ''), $m);
        $filename = $m[1] ?? 'file';

        $tmpPath = sys_get_temp_dir() . '/' . uniqid('upload_', true);
        file_put_contents($tmpPath, $content);

        try {
            $safeFilename = $this->fileValidator->sanitizeFilename($filename);
            $mime         = $this->fileValidator->detectMimeType($tmpPath);

            $year = date('Y');
            $month = date('m');
            $dir = $this->projectDir . '/public/uploads/' . $subDir . '/' . $year . '-' . $month;
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }

            $storedName = uniqid('', true) . '_' . $safeFilename;
            rename($tmpPath, $dir . '/' . $storedName);

            return [
                'url'      => '/uploads/' . $subDir . '/' . $year . '-' . $month . '/' . $storedName,
                'filename' => $safeFilename,
                'filemime' => $mime,
                'size'     => strlen($content),
            ];
        } catch (\Throwable $e) {
            if (file_exists($tmpPath)) {
                unlink($tmpPath);
            }
            throw new \RuntimeException($e->getMessage(), 0, $e);
        }
    }
}
