<?php

namespace Zoomyboy\MedialibraryHelper\Rules;

use Illuminate\Contracts\Validation\InvokableRule;
use Spatie\MediaLibrary\HasMedia;
use Illuminate\Validation\Factory;
use Illuminate\Validation\Rule;
use Spatie\MediaLibrary\MediaCollections\MediaCollection;

class ModelRule implements InvokableRule
{

    public ?string $collection;
    public ?int $id;
    public ?string $model;

    /**
     * @param array{?id: int, ?collection: string, ?model: string} $attribute
     */
    public function __invoke($attribute, $value, $fail)
    {
        app(Factory::class)->make([$attribute => $value], [
            "{$attribute}.id" => 'nullable|integer|gt:0',
            "{$attribute}.model" => ['required', 'string', Rule::in(app('media-library-helpers')->keys())],
            "{$attribute}.collection_name" => 'required|string',
        ])->validate();


        $this->model = data_get($value, 'model');
        $this->id = data_get($value, 'id');
        $this->collection = data_get($value, 'collection_name');

        if (is_null($this->id)) {
            $this->validateDeferred($attribute, $value);
            return;
        }

        $model = app('media-library-helpers')->get($this->model);
        app(Factory::class)->make([$attribute => $value], [
            "{$attribute}.collection_name" => ['required', Rule::in((new $model())->getRegisteredMediaCollections()->pluck('name'))],
            "{$attribute}.id" => ['required', 'exists:' . (new $model)->getTable() . ',id'],
        ])->validate();
    }

    public function validateDeferred($attribute, $value): void
    {
        app(Factory::class)->make([$attribute => $value], [
            "{$attribute}.model" => ['required', 'string', Rule::in(app('media-library-helpers')->keys())],
            "{$attribute}.collection_name" => 'required|string',
        ])->validate();

        $model = app('media-library-helpers')->get($this->model);

        app(Factory::class)->make([$attribute => $value], [
            "{$attribute}.collection_name" => ['required', Rule::in((new $model())->getRegisteredMediaCollections()->pluck('name'))],
        ])->validate();
    }


    /**
     * @param array{?id: int, ?collection_name: string, ?model: string} $modelParam
     */
    public static function getModel($modelParam): HasMedia
    {
        $model = static::getModelClassName($modelParam);

        return $model::find($modelParam['id']);
    }

    /**
     * @param array{?id: int, ?collection_name: string, ?model: string} $modelParam
     * @return class-string<HasMedia>
     */
    public static function getModelClassName($modelParam): string
    {
        return app('media-library-helpers')->get($modelParam['model']);
    }

    /**
     * @param array{?id: int, ?collection_name: string, ?model: string} $modelParam
     */
    public static function getCollection($modelParam): MediaCollection
    {
        $className = static::getModelClassName($modelParam);

        return (new $className)->getMediaCollection($modelParam['collection_name']);
    }
}
