<?php

namespace Planaday\Html\Tags\Form\Booking\MaterialsChecklist;

use ArrayAccess;
use Countable;
use Planaday\Api\ApiException\InvalidResponseException;
use Planaday\Config\Booking\Form\Materials\MaterialSettings;
use Planaday\Entities\Booking\PostRequest\BookingFormFieldEnum;
use Planaday\Entities\CostDataUtility;
use Planaday\Entities\Course\CourseController;
use Planaday\Entities\Course\DTO\CourseMaterial;
use Planaday\Entities\Course\Exception\CourseNotFoundException;
use Planaday\Html\Tags\Form\DataInputFieldTag;
use Planaday\Html\Tags\InvalidAttributesException;
use Planaday\Platform\PlatformAbstraction\LocalizationController;
use Planaday\Utility\DependencyInjection\Container;
use Planaday\Utility\DependencyInjection\InjectionImpossibleException;
use Traversable;

class MaterialsChecklist extends DataInputFieldTag {
	const TAG = 'materials-checklist';
	const DEFAULT_TEMPLATE = 'materialsChecklist';
	const COURSE_ID_ATTRIBUTE = 'data-course-id';
	protected string $fieldName = BookingFormFieldEnum::MATERIALS;

	protected CourseController $courseController;
	protected CostDataUtility $costUtility;
	protected MaterialSettings $materialSettings;
	protected LocalizationController $translator;

	/**
	 * @param Container $registry
	 *
	 * @throws InjectionImpossibleException
	 */
	public function __construct(Container $registry) {
		$this->materialSettings = $registry->getInstance(MaterialSettings::class);
		$this->courseController = $registry->getInstance(CourseController::class);
		$this->costUtility = $registry->getInstance(CostDataUtility::class);
		$this->translator = $registry->getInstance(LocalizationController::class);
		parent::__construct(__DIR__, self::DEFAULT_TEMPLATE, $registry);
	}

	public function buildTag(): string {
		$parser = $this->getNewParser();
		$parser->addStylesheet($this->getStylePath());

		try{
			$courseIdString = $this->attributes[self::COURSE_ID_ATTRIBUTE] ?? null;
			if ($courseIdString === null) throw new InvalidAttributesException();

			$courseId = filter_var($courseIdString, FILTER_VALIDATE_INT);
			if ($courseId === false) throw new InvalidAttributesException();

			$materials = $this->courseController->getMaterialsCourse($courseId);
			$checklist = $this->getMaterialsChecklist($materials);
		}
		catch ( InvalidResponseException ) {
			$checklist = $this->getNewParser()->parse($this->getErrorTemplate('', 'serverError'));
		}
		catch ( CourseNotFoundException ) {
			$checklist = $this->getNewParser()->parse($this->getErrorTemplate('', 'courseNotFound'));
		}
		catch ( InvalidAttributesException ) {
			$checklist = $this->getNewParser()->parse($this->getErrorTemplate('', 'attributeError'));
		}

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

	/**
	 * @param ArrayAccess<int|string,CourseMaterial>&Traversable<int|string,CourseMaterial>&Countable $materials
	 *
	 * @return string
	 */
	private function getMaterialsChecklist(ArrayAccess&Traversable&Countable $materials):string {
		$output = '';

		$showBothPrices = $this->materialSettings->isShowBothWithAndWithoutTaxPrice();
		$showDescription = $this->materialSettings->isShowDescriptionMaterials();

		foreach ($materials as $material){
			$parser = $this->getNewParser();

			$parser->setData('materialName', $material->getName());
			$parser->setData('materialId', $material->getId());
			$parser->setUnsafeData('materialDescription', $material->getDescription());

			if ($material->isInvoicedPerCompany()){
				$pricelabel = $this->costUtility->getPriceString($material->getCostsData(), $showBothPrices);
				if ($material->getAmount() > 1) {
					$pricelabel .= ' x ' . $material->getAmount() . $this->translator->translate(' stuks');
				}
				$parser->setData('priceLabel', $pricelabel);
			} else {
				$parser->setData('priceLabel', $this->costUtility->getPriceString($material->getCostsData(), $showBothPrices, $material->isInvoicedPerStudent()));
			}

			$parser->setCondition('showDescription', $showDescription);

			$output .= $parser->parse($this->getTemplate('Material'));
		}

		return $output;
	}
}