<?php declare(strict_types=1);

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

final readonly class Permission implements ValidationRule
{
    /**
     * Run the validation rule.
     *
     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (!is_string($value) && !is_array($value)) {
            $fail('validation.no_type')->translate(['type' => 'string, array']);
            return;
        }

        if (is_string($value)) {
            $this->validatePermission($value, $fail);
        }

        if (is_array($value)) {
            foreach ($value as $item) {
                $this->validatePermission($item, $fail);
            }
        }
    }

    private function validatePermission(string $value, Closure $fail): void
    {
        $value = explode('.', $value, 2);

        if (count($value) !== 2) {
            $fail('validation.enum')->translate();
            return;
        }

        list($permissionEnum, $permission) = $value;
        $permissionEnum = \App\Enums\Permission::tryFrom($permissionEnum);
        if (is_null($permissionEnum)) {
            $fail('validation.enum')->translate();
            return;
        }

        $permissions = $permissionEnum->getPermissions();
        if (!isset($permissions[$permission])) {
            $fail('validation.enum')->translate();
            return;
        }
    }
}