<?php

namespace Planaday\Html\Tags\Course\CourseCalendarShortcode;

use ArrayAccess;
use Countable;
use Planaday\Api\ApiException\InvalidResponseException;
use Planaday\Config\Course\Calendar\CalendarSettings;
use Planaday\Entities\Course\DTO\Course;
use Planaday\Entities\Location\Exception\LocationNotFoundException;
use Planaday\Entities\Location\LocationController;
use Planaday\Html\Tags\Course\CourseListShortcode\CourseListShortcode;
use Planaday\Utility\DependencyInjection\Container;
use Planaday\Utility\DependencyInjection\InjectionImpossibleException;
use Traversable;

class CourseCalendarShortcode extends CourseListShortcode {
	const TAG = 'course-calendar';
	const DEFAULT_TEMPLATE = 'v3Calendar';
	const DEFAULT_TEMPLATE_V6 = 'v6Calendar';

	protected LocationController $locationController;
	protected CalendarSettings $calendarSettings;

	/**
	 * @param Container $registry
	 *
	 * @throws InjectionImpossibleException
	 */
	public function __construct(Container $registry) {
		$this->calendarSettings   = $registry->getInstance(CalendarSettings::class);
		$this->locationController = $registry->getInstance(LocationController::class);

		$defaultTemplate = match ( $this->calendarSettings->getCalendarVersion() ) {
			1 => ( self::DEFAULT_TEMPLATE_V6 ),
			default => ( self::DEFAULT_TEMPLATE ),
		};

		parent::__construct($registry, __DIR__,  $defaultTemplate);
	}

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

		try{
			$attributeSearchArguments = $this->getAttributeSearchArgs();
			$allSearchArgs = $this->getAllSearchArgs($this->getPostSearchArgs(), $attributeSearchArguments);

			$courses = $this->getCourseList($allSearchArgs);

			if (count($courses) == 0){
				$this->checkAndSetNoCoursesError($parser, $allSearchArgs, $attributeSearchArguments);
				$parser->setCondition('showCalendar', false);
			} else {
				$dataArray = $this->buildDataBundle($courses);
				$dataJson = json_encode( $dataArray, JSON_PRETTY_PRINT );
				if ($dataJson === false) $dataJson = '';

				$parser->setUnsafeData('dataJson', $dataJson);
				$parser->setUnsafeData('enableMouseOver', ($this->calendarSettings->isShowMouseoverText() ? 'true' : 'false'));
				$parser->setCondition('showCalendar', true);
			}

			$template = $this->getTemplate();
		}
		catch ( InvalidResponseException $e ) {
			$this->initializeExceptionData($e, $parser);
			$template = $this->getServerErrorTemplate();
		}

		return $parser->parse($template);
	}

	/**
	 * @param Countable&Traversable<Course>&ArrayAccess<Course> $courses
	 *
	 * @return array<mixed>
	 */
	private function buildDataBundle( ArrayAccess&Traversable&Countable $courses):array {
		$dataArray = [];

		foreach ( $courses as $course ) {

			if ($this->calendarSettings->isShowAllDayParts()){
				$dayParts = $course->getDayParts();
			} else {
				$dayParts = [$course->getEarliestDayPart($this->generalSettings->isELearningCountsAsStart())];
			}

			foreach ($dayParts as $dayPart) {
				try {
					$locationId = $dayPart->getLocationIds()[0] ?? null;
					$location = null;

					if ($locationId > 0) {
						$location = $this->locationController->getLocation( $locationId );
					}
				} catch ( InvalidResponseException|LocationNotFoundException ) {
					$location = null;
				}

				$start = $dayPart->getStartTime();
				$end   = $dayPart->getEndTime();

				$calenderDate = $start->format('Y-m-d');
				$date         = $start->format('d-m-Y');
				$description  = "<b> " . $course->getName() . ": " . $dayPart->getName() . "</b><br/>" .
				                "Begint op " . $date . " (" . $start->format('H:i') . ($end ? " - " . $end->format('H:i') : "") . ")<br/>" .
				                "Locatie: " . ( $location ? $location->getCity() : '-' );

				$dataArray[]  = [
					"title"       => $course->getName() . ": " . $dayPart->getName() . " in " . ( $location ? $location->getCity() : '-' ),
					"description" => $description,
					"allDay"      => false,
					"start"       => $calenderDate . "T" . $start->format('H:i'),
					"editable"    => false,
					"color"       => $this->calendarSettings->getBackgroundColor(),
					"textColor"   => $this->calendarSettings->getTextColor(),
					"url"         => $this->courseUtility->getDetailLink($course),
					"end"         => $calenderDate . ($end ? "T" . $end->format('H:i') : ""),
				];
			}
		}

		return $dataArray;
	}
}