<?php

namespace App\Services;

use App\Models\Media;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;

class MediaUploadService
{
    private const DISK = 'uploads';

    public function store(UploadedFile $file, string $collection, ?User $user = null): Media
    {
        $user   ??= auth()->user();
        $folder   = $this->userFolder($user);
        $filename = $this->uniqueFilename($folder, $file->getClientOriginalName());

        $path = $file->storeAs($folder, $filename, self::DISK);

        return Media::create([
            'user_id'       => $user->id,
            'disk'          => self::DISK,
            'path'          => $path,
            'filename'      => $filename,
            'original_name' => $file->getClientOriginalName(),
            'mime_type'     => $file->getMimeType(),
            'size'          => $file->getSize(),
            'type'          => $this->typeFromMime($file->getMimeType()),
            'collection'    => $collection,
        ]);
    }

    public function delete(Media $media): void
    {
        Storage::disk($media->disk)->delete($media->path);
        $media->delete();
    }

    /**
     * Deletes the most recent media of a given collection for a user (e.g. replacing a
     * singleton asset like the business logo, which orphaned the previous file before).
     */
    public function replaceLatestInCollection(User $user, string $collection, UploadedFile $file): Media
    {
        Media::where('user_id', $user->id)
            ->where('collection', $collection)
            ->get()
            ->each(fn (Media $old) => $this->delete($old));

        return $this->store($file, $collection, $user);
    }

    private function userFolder(User $user): string
    {
        return $user->username;
    }

    private function uniqueFilename(string $folder, string $originalName): string
    {
        $base = preg_replace('/[^a-zA-Z0-9\-_]/', '', str_replace(' ', '-', pathinfo($originalName, PATHINFO_FILENAME)));
        $base = trim($base, '-') ?: 'file';
        $ext  = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));

        $filename = "{$base}.{$ext}";
        $counter  = 1;
        while (Storage::disk(self::DISK)->exists("{$folder}/{$filename}")) {
            $filename = "{$base}-{$counter}.{$ext}";
            $counter++;
        }

        return $filename;
    }

    private function typeFromMime(?string $mime): ?string
    {
        if (!$mime) {
            return null;
        }

        return match (true) {
            str_starts_with($mime, 'image/') => 'image',
            str_starts_with($mime, 'video/') => 'video',
            default => 'document',
        };
    }
}
