/home/bdqbpbxa/dev-subdomains/api-uniferx.goodface.com.ua/vendor/eminiarts/nova-tabs/src/Tabs.php
<?php

declare(strict_types=1);

namespace Eminiarts\Tabs;

use Closure;
use Eminiarts\Tabs\Contracts\TabContract;
use Illuminate\Http\Resources\MergeValue;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use Laravel\Nova\Contracts\ListableField;
use Laravel\Nova\Panel;
use Laravel\Nova\ResourceToolElement;
use function is_array;
use function is_callable;

class Tabs extends Panel
{
    /**
     * @var mixed
     */
    public $defaultSearch = false;

    /**
     * @var bool
     */
    public bool $showTitle = false;

    /**
     * @var bool
     */
    public bool $selectFirstTab = true;

    private int $tabsCount = 0;

    public $slug = null;

    private string $preservedName;

    public bool $retainTabPosition = false;

    public $currentColor = null;
    public string $errorColor = 'red';

    /**
     * Create a new panel instance.
     *
     * @param  string  $name
     * @param  (\Closure():array|iterable)|array  $fields
     * @return void
     */
    public function __construct($name, $fields = [])
    {
        $this->name = $name;
        $this->preservedName = $name;
        $this->withComponent('tabs');

        parent::__construct($name, $fields);
    }


    /**
     * Set the tabs slug.
     *
     * @param  string|boolean $slug
     * @return $this
     */
    public function withSlug($slug): Tabs
    {

        $this->slug = is_bool($slug) ? ($slug ? Str::slug($this->preservedName, '_') : null) : $slug;

        return $this;
    }

    /**
     * Set the color for current tabs.
     *
     * @param string $color
     * @return $this
     */
    public function withCurrentColor(string $color): Tabs
    {

        $this->currentColor = $color;

        return $this;
    }

    /**
     * Set the color for tabs with errors.
     *
     * @param  string $color
     * @return $this
     */
    public function withErrorColor(string $color): Tabs
    {

        $this->errorColor = $color;

        return $this;
    }

    /**
     * Remember tab position across detail/edit
     *
     * @param  Boolean $retain
     * @return $this
     */
    public function rememberTabs($retain): Tabs
    {
        $this->retainTabPosition = $retain;
        return $this;
    }

    /**
     * Prepare the given fields.
     *
     * @param  Closure|array  $fields
     * @return array
     */
    protected function prepareFields($fields): array
    {
        $this->convertFieldsToTabs($fields)
            ->filter(static function (Tab $tab): bool {
                return $tab->shouldShow();
            })
            ->each(function (Tab $tab): void {
                $this->addFields($tab);
            });


        return $this->data ?? [];
    }

    /**
     * @param $fields
     * @return Collection<TabContract>
     */
    private function convertFieldsToTabs($fields): Collection
    {
        $fieldsCollection = collect(
            is_callable($fields) ? $fields() : $fields
        );

        return $fieldsCollection->map(function ($fields, $key) {
            return $this->convertToTab($fields, $key);
        })->values();
    }

    /**
     * @param  mixed  $fields
     * @param  string|int  $key
     * @return Tab
     */
    private function convertToTab($fields, $key): TabContract
    {
        if ($fields instanceof TabContract) {
            return $fields;
        }

        $this->tabsCount++;

        if ($fields instanceof Panel) {
            return new Tab($fields->name, $fields->data, $this->tabsCount);
        }

        /**
         * If a field is not nested into an array or a Tab object
         * it acts as a tab in itself
         *
         * @link https://github.com/eminiarts/nova-tabs/issues/141
         */
        if (!is_array($fields)) {
            return new Tab($fields->name, [$fields], $this->tabsCount);
        }

        return new Tab($key, $fields, $this->tabsCount);
    }

    /**
     * Add fields to the Tab.
     *
     * @param  TabContract  $tab
     * @return $this
     */
    public function addFields(TabContract $tab): self
    {
        $this->tabs[] = $tab;

        foreach ($tab->getFields() as $field) {
            if ($field instanceof Panel) {
                $field->assignedPanel = $this;

                $this->addFields(
                    new Tab($field->name, $field->data)
                );
                continue;
            }

            if ($field instanceof MergeValue) {
                if (!isset($field->panel)) {
                    $field->assignedPanel = $this;
                    $field->panel = $this->name;
                }

                $this->addFields(
                    tap(new Tab($tab->getTitle(), $field->data), function (TabContract $newTab) use ($tab): void {
                        if ($tab->getName() !== $tab->getTitle()) {
                            $newTab->name($tab->getName());
                        }
                    })
                );
                continue;
            }

            $field->panel = $this->name;
            $field->assignedPanel = $this;

            $meta = [
                'tab' => $tab->getName(),
                'tabSlug' => $tab->getSlug(),
                'tabPosition' => $tab->getPosition(),
                'tabInfo' => Arr::except($tab->toArray(), ['fields', 'slug'])
            ];

            if ($field instanceof ListableField) {
                $meta += [
                    'listable' => false,
                    'listableTab' => true,
                ];
            }

            $field->withMeta($meta);

            $this->data[] = $field;
        }

        return $this;
    }

    /**
     * Show default Search if you need more space
     *
     * @param  bool  $value
     *
     * @return $this
     */
    public function defaultSearch(bool $value = true): self
    {
        $this->defaultSearch = $value;

        return $this;
    }

    /**
     * Whether the show the title
     *
     * @param bool $show
     * @return $this
     */
    public function showTitle(bool $show = true): self
    {
        $this->showTitle = $show;

        return $this;
    }

    /**
     * Prepare the panel for JSON serialization.
     *
     * @return array
     */
    public function jsonSerialize(): array
    {
        $result = array_merge(parent::jsonSerialize(), [
            'defaultSearch' => $this->defaultSearch,
            'showTitle' => $this->showTitle,
            'slug' => $this->slug,
            'retainTabPosition' => $this->retainTabPosition,
            'currentColor' => $this->currentColor,
            'errorColor' => $this->errorColor
        ]);

        return $result;
    }
}