<?php

namespace Planaday\Html\Tags\Admin\Form\AdminOptionInput;

use Planaday\Config\OptionGroups\OptionCluster;
use Planaday\Config\OptionTypes\Option;
use Planaday\Config\OptionTypes\PageOption;
use Planaday\Config\OptionTypes\RadioOption;
use Planaday\Html\HtmlParser;
use Planaday\Html\Tags\Admin\Form\OptionGroupArea\OptionGroupArea;
use Planaday\Html\Tags\Form\GenericInput\CheckboxInput\CheckboxInput;
use Planaday\Html\Tags\Form\GenericInput\MappedIntRadio\MappedIntRadio;
use Planaday\Html\Tags\Form\GenericInput\PageSelect\PageSelect;
use Planaday\Html\Tags\Form\GenericInput\TextInput\TextInput;
use Planaday\Html\Tags\Form\SelectableDataInputFieldTag;
use Planaday\Html\Tags\Tag;
use Planaday\Utility\DependencyInjection\ComponentRegistry;
use Planaday\Utility\DependencyInjection\InjectionImpossibleException;

class AdminOptionInput extends SelectableDataInputFieldTag {

	const TAG = 'admin-form-option-input';
	const DEFAULT_TEMPLATE = 'optionInput';
	const OPTION_GROUP_ARRAY_CONTEXT = OptionGroupArea::OPTION_GROUP_ARRAY_CONTEXT;
	const OPTION_GROUP_INDEX_ATTRIBUTE = OptionGroupArea::OPTION_GROUP_INDEX_ATTRIBUTE;

	/**
	 * @param ComponentRegistry $registry
	 *
	 * @throws InjectionImpossibleException
	 */
	public function __construct(ComponentRegistry $registry) {
		parent::__construct(__DIR__, self::DEFAULT_TEMPLATE, $registry);
	}

	public function buildTag(): string {
		$optionGroupArray = $this->context[self::OPTION_GROUP_ARRAY_CONTEXT] ?? null;
		$index = $this->attributes[self::OPTION_GROUP_INDEX_ATTRIBUTE] ?? null;

		if (!is_array($optionGroupArray)){
			$this->logError(self::TAG . ' was called without array in optionGroupArray context');
			return '';
		}
		if ($index === null){
			$this->logError(self::TAG . ' was called without a valid index');
			return '';
		}
		if (!isset($optionGroupArray[$index])){
			$this->logError(self::TAG . ' was called without the anything at index ' . $index);
			return '';
		}
		if (!($optionGroupArray[$index] instanceof Option || $optionGroupArray[$index] instanceof OptionCluster)){
			$this->logError(self::TAG . ' was called with the wrong type at index ' . $index);
			return '';
		}

		$parser = $this->getNewParser();

		$option = $optionGroupArray[$index];
		$optionTags = '';
		$template = 'optionInput';

		if ($option instanceof OptionCluster){
			if ($option->getType() === 'null'){
				$this->logError(self::TAG . ' was called with an empty cluster');
				return '';
			}

			$optionTagsArray = [];
			foreach ($option->getLayout() as $key => $item){
				$optionTag = "<label class='pad-admin-option-key'>";
				$optionTag .= $this->getTagOption($item, $parser, true);
				$optionTag .= " $key </label>";
				$optionTagsArray[] = $optionTag;
			}
			$optionTags = implode('<br>', $optionTagsArray);

			$parser->setData('title', $option->getName());
			$template = 'optionInputCluster';
		} else {
			$optionTags .= $this->getTagOption($option, $parser);
			$parser->setData('title', $option->getTitle());
		}

		$parser->setUnsafeData('input-tags', $optionTags);
		$parser->setUnsafeData('description', $option->getDescription());

		return $parser->parse($this->getTemplate('', $template));
	}

	/**
	 * @param Option<int|string, int|string|null> $option
	 * @param HtmlParser $parser
	 * @param bool $cluster
	 *
	 * @return string
	 */
	private function getTagOption(Option $option, HtmlParser $parser, bool $cluster = false): string {
		$tag = '';
		$template = 'adminOption';
		$attributes = [
			SelectableDataInputFieldTag::FIELD_NAME_ATTRIBUTE => $option->getIndex(),
			SelectableDataInputFieldTag::FIELD_TITLE_ATTRIBUTE => $option->getTitle(),
			SelectableDataInputFieldTag::FIELD_SET_VALUE_ATTRIBUTE => '' . $option->getValue(),
			SelectableDataInputFieldTag::PLACEHOLDER_ATTRIBUTE => '' . ($option->getDefaultValue() ?? $option->getTitle()),
		];

		switch ($option->getType()){
			case 'radio':
				$tag = MappedIntRadio::TAG;
				if ($option instanceof RadioOption) $parser->addContext(MappedIntRadio::MAP_CONTEXT_INDEX, $option->getMapping());
				break;
			case 'int':
			case 'string':
				$tag = TextInput::TAG;
				break;
			case 'text':
				$tag = TextInput::TAG;
				$template .= 'TextArea';
				break;
			case 'bool':
				$tag = CheckboxInput::TAG;
				$attributes[SelectableDataInputFieldTag::FIELD_SET_VALUE_ATTRIBUTE] = '1';
				$attributes[CheckboxInput::FALSE_VALUE_ATTRIBUTE] = '0';
				if ($option->getValue()) $attributes[CheckboxInput::CHECKED_ATTRIBUTE] = 'soft';
				break;
			case 'page':
				$tag = PageSelect::TAG;
				if ($option instanceof PageOption) $attributes[PageSelect::NEED_TAG_ATTRIBUTE] = $option->getShortcode() ?? '';
				break;
		}

		if ($tag === ''){
			$this->logError(self::TAG . ' was called with an unknown option type');
			return '';
		}

		return Tag::getParsableTag($tag, $attributes + [
				Tag::TEMPLATE_ATTRIBUTE => $cluster ? $template . 'Cluster' : $template,
				]);
	}
}