<?php

namespace Planaday\Utility\FormBuilder\InputFields;

use ArrayAccess;
use Countable;
use Planaday\Utility\FormBuilder\DataTypes\ArrayType;
use Planaday\Utility\FormBuilder\InputField;
use Planaday\Utility\FormBuilder\InvalidFormDataException;
use Traversable;

/**
 * @template T
 * @implements InputField<T[]>
 */
class MultiSelectInput implements InputField {
	use BasicInputField{
		validate as traitValidate;
	}

	/**
	 * @param ArrayType<T> $type
	 */
	public function __construct(
		ArrayType $type
	) {
		$this->dataType = $type;
	}

	protected array $options = [];
	protected bool $allowCustom = false;
	protected ?InputField $customInput = null;

	public function setOptions( iterable $options ): self {
		$this->options = [];

		foreach ( $options as $option ) {
			if ( is_array( $option ) ) {
				$this->options[] = $option;
				continue;
			}

			$this->options[] = [
				'value' => $option,
				'label' => $option
			];
		}

		return $this;
	}

	public function getOptions(): array {
		return $this->options;
	}

	public function allowCustom(): self {
		$this->allowCustom = true;
		return $this;
	}

	public function setCustomInput( InputField $customInput ): self {
		$this->customInput = $customInput;
		return $this;
	}

	public function validate(): bool|InvalidFormDataException {
		if (!$this->validateConditions()) return true;
		$basicValidate = $this->traitValidate();
		if ($this->allowCustom) {
			return $basicValidate;
		}

		if ($this->value === null) return true;
		foreach ( $this->value as $val ) {
			$inArray = false;

			foreach ( $this->options as $option ) {
				if ( $option['value'] === $val ) {
					$inArray = true;
					break;
				}
			}

			if ( !$inArray ) {
				if ( $basicValidate === true ) {
					$basicValidate = new InvalidFormDataException();
				}

				$basicValidate->addError( 'MultiSelectInput', 'Input was not a valid option.' );
				return $basicValidate;
			}
		}

		return $basicValidate;
	}

	public function getImplJson(): array {
		return [
			"type"       => 'multiSelect',
			"options"     => $this->options,
			"allowCustom" => $this->allowCustom,
			"customInput" => $this->customInput
		];
	}
}