<?php

namespace App\Services\Media;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class MediaService
{
    public function syncCollection(
        HasMedia $model,
        string $collection,
        ?array $newFiles,
        ?array $removeIds,
        int $maxFiles,
        ?string $type = null,
        bool $required = false,
        ?string $errorKey = null,
    ): void {
        $newFiles = array_values(array_filter($newFiles ?? []));

        if ($maxFiles === 1 && $newFiles !== []) {
            $model->clearMediaCollection($collection);
        } elseif ($removeIds !== null && $removeIds !== []) {
            $model->getMedia($collection)
                ->whereIn('id', $removeIds)
                ->each->delete();
        }

        if ($maxFiles === 1) {
            $newFiles = array_slice($newFiles, 0, 1);
        }

        $currentCount = $model->getMedia($collection)->count();

        if ($currentCount + count($newFiles) > $maxFiles) {
            throw ValidationException::withMessages([
                $errorKey ?? $collection => "Maksimal {$maxFiles} gambar per item.",
            ]);
        }

        foreach ($newFiles as $file) {
            $this->addUploadedFile($model, $file, $collection, $type);
        }

        if ($model instanceof Model) {
            $model->unsetRelation('media');
        }

        if ($required && $model->getMedia($collection)->isEmpty()) {
            throw ValidationException::withMessages([
                $errorKey ?? $collection => 'Foto wajib diisi.',
            ]);
        }
    }

    public function addUploadedFile(
        HasMedia $model,
        UploadedFile $file,
        string $collection,
        ?string $type = null,
    ): Media {
        return $model->addMedia($file)
            ->withCustomProperties($this->customProperties($model, $type ?? $collection))
            ->toMediaCollection($collection);
    }

    public function addBase64Image(
        HasMedia $model,
        string $base64Photo,
        string $collection,
        ?string $type = null,
        string $extension = 'jpg',
    ): Media {
        $image = base64_decode(
            (string) preg_replace('#^data:image/\w+;base64,#i', '', $base64Photo),
            true,
        );

        if ($image === false) {
            throw ValidationException::withMessages([
                'photo' => 'Foto tidak valid.',
            ]);
        }

        $filename = sprintf('%s.%s', Str::uuid(), $extension);
        $tempPath = 'temp/'.$filename;

        Storage::disk('local')->put($tempPath, $image);

        try {
            return $model->addMedia(Storage::disk('local')->path($tempPath))
                ->usingFileName($filename)
                ->withCustomProperties($this->customProperties($model, $type ?? $collection))
                ->toMediaCollection($collection);
        } finally {
            Storage::disk('local')->delete($tempPath);
        }
    }

    public function replaceSingleFile(
        HasMedia $model,
        UploadedFile $file,
        string $collection,
        ?string $type = null,
    ): Media {
        $model->clearMediaCollection($collection);

        return $this->addUploadedFile($model, $file, $collection, $type);
    }

    private function customProperties(HasMedia $model, ?string $type): array
    {
        $properties = [
            'module' => method_exists($model, 'mediaModuleName')
                ? $model::mediaModuleName()
                : 'media',
        ];

        if ($type !== null && $type !== '') {
            $properties['type'] = $type;
        }

        return $properties;
    }
}
