<?php

namespace Ignite\Core\Http\Forms\Admin;

use Ignite\Core\Entities\Group;
use Illuminate\Validation\Rule;
use Kris\LaravelFormBuilder\Form;

class GroupForm extends Form
{
    public function buildForm()
    {
        $this->add('name', 'text', $this->getNameOptions());

        if (! $this->model instanceof Group || ($this->model instanceof Group && $this->model->isUserDefined())) {
            $this->add('level', 'select', $this->getLevelOptions());
        } else {
            $this->add('level', 'hidden', $this->getLevelHiddenOptions());
        }


        $this->add('description', 'textarea', $this->getDescriptionOptions());
        $this->add('status', 'toggle');

        $this->add('submit', 'submit', [
            'attr' => ['class' => 'btn btn-primary pull-right btn-save'],
            'label' => 'Save'
        ]);
    }

    /**
     * The options for the name field.
     *
     * @return array
     */
    private function getNameOptions()
    {
        $rules = [
            'required',
        ];

        if ($groupId = $this->getData('group')) {
            $rules[] = $this->getUniqueRuleFor('name')->ignore($groupId);
        } else {
            $rules[] = $this->getUniqueRuleFor('name');
        }

        return [
            'rules' => $rules
        ];
    }

    /**
     * The options for the level field.
     *
     * @return array
     */
    private function getLevelOptions()
    {
        $options = $this->getLevelSelections();
        $rules = $this->getLevelRules($options);
        $model = $this->getModel();
        $levelsTaken = Group::all()->pluck('level');
        $levelsRemaining = $options->filter(function ($option) use ($levelsTaken, $model) {
            return ! $levelsTaken->contains($option) || ($model instanceof Group && $model->level === $option);
        });

        return [
            'rules' => $rules,
            'choices' => $levelsRemaining->combine($levelsRemaining)->toArray()
        ];
    }

    /**
     * The options for the level field.
     *
     * @return array
     */
    private function getLevelHiddenOptions()
    {
        return [
            'rules' => $this->getLevelRules($this->getLevelSelections()),
        ];
    }

    /**
     * The level field selections.
     *
     * @return \Illuminate\Support\Collection
     */
    private function getLevelSelections()
    {
        return collect([
            1, 2, 4, 8, 16, 32, 64, 128, 256, 512,
            1024, 2048, 4096, 8192, 16384
        ]);
    }

    /**
     * The level field validation rules.
     *
     * @param  \Illuminate\Support\Collection $options
     * @return array
     */
    private function getLevelRules($options)
    {
        $rules = [
            'required',
            'numeric',
            Rule::in($options->combine($options)->toArray()),
        ];

        if ($groupId = $this->getData('group')) {
            $rules[] = $this->getUniqueRuleFor('level')->ignore($groupId);
        } else {
            $rules[] = $this->getUniqueRuleFor('level');
        }

        return $rules;
    }

    /**
     * The options for the description field.
     *
     * @return array
     */
    private function getDescriptionOptions()
    {
        return [
            'rules' => 'required'
        ];
    }

    /**
     * Create a unique rule for the given field.
     *
     * @param  string $field
     * @return \Illuminate\Validation\Rules\Unique
     */
    private function getUniqueRuleFor($field)
    {
        return Rule::unique(Group::query()->newModelInstance()->getTable(), $field);
    }
}
