<?php

namespace Planaday\Html\Tags\Course\CourseBookingForm;

use Planaday\Api\ApiException\InvalidResponseException;
use Planaday\Config\Booking\Form\FormSettings;
use Planaday\Config\Course\CourseSettings;
use Planaday\Config\Course\General\GeneralSettings;
use Planaday\Config\Payment\PaymentSettings;
use Planaday\Entities\Booking\BookingDatabase;
use Planaday\Entities\Booking\BookingFormPostService;
use Planaday\Entities\Booking\Enum\TransactionStatus;
use Planaday\Entities\Booking\Exception\CourseFullException;
use Planaday\Entities\Booking\PostRequest\BookingFormFieldEnum;
use Planaday\Entities\Course\CourseController;
use Planaday\Entities\Course\DTO\DayPartDisplayTypes;
use Planaday\Entities\Course\Exception\CourseNotFoundException;
use Planaday\Entities\PostEntities;
use Planaday\Html\Tags\Form\DataInputFieldTag;
use Planaday\Html\Tags\Form\SelectableDataInputFieldTag;
use Planaday\Payment\Interfaces\PaymentHandler;
use Planaday\Platform\PlatformAbstraction\DataHandler;
use Planaday\Platform\PlatformAbstraction\UrlHandler;
use Planaday\Utility\DataGrouping\UUIDGenerator;
use Planaday\Utility\DependencyInjection\Container;
use Planaday\Utility\DependencyInjection\InjectionImpossibleException;
use Planaday\Utility\GeneralTermEnum;

class CourseBookingForm extends DataInputFieldTag {
	const TAG = 'course-booking-form';
	const DEFAULT_TEMPLATE = 'bookingForm';
	protected string $fieldName = PostEntities::BOOKING_FORM;

	protected CourseController $courseController;
	protected DataHandler $dataHandler;
	protected BookingFormPostService $bookingFormPostService;
	protected UrlHandler $urlHandler;
	protected PaymentSettings $paymentSettings;
	protected FormSettings $formSettings;
	protected bool $includeOptionsAvailability;
	private GeneralSettings $generalSettings;

	/**
	 * @param Container $registry
	 *
	 * @throws InjectionImpossibleException
	 */
	public function __construct(
		protected Container $registry
	) {
		$this->includeOptionsAvailability = $registry->getInstance(CourseSettings::class)->getGeneralSettings()->isIncludeOptionInCount();
		$this->formSettings               = $registry->getInstance(FormSettings::class);
		$this->bookingFormPostService     = $registry->getInstance(BookingFormPostService::class);
		$this->courseController = $registry->getInstance(CourseController::class);
		$this->dataHandler = $registry->getInstance(DataHandler::class);
		$this->paymentSettings = $registry->getInstance( PaymentSettings::class);
		$this->urlHandler = $registry->getInstance(UrlHandler::class);
		$this->generalSettings = $this->registry->getInstance(CourseSettings::class)->getGeneralSettings();
		parent::__construct(__DIR__, self::DEFAULT_TEMPLATE, $registry);
	}

	public function buildTag(): string {
		$bookingUUID = $this->urlHandler->getUrlQueryField( $this->pluginData->getShortPrefix() . GeneralTermEnum::BOOKING_UUID_URL_QUERY);
		$bookingPassword = $this->urlHandler->getUrlQueryField( $this->pluginData->getShortPrefix() . GeneralTermEnum::BOOKING_PASSCODE_URL_QUERY);
		if (isset($bookingPassword, $bookingUUID)) {
			$this->logInfo('Booking UUID and Password found in URL: ' . $bookingUUID . ', ' . $bookingPassword);

			try {
				$bookingDB = $this->registry->getInstance(BookingDatabase::class);
				if ($bookingDB->checkPasswordBooking($bookingUUID, $bookingPassword)){
					$booking = $bookingDB->getBooking($bookingUUID);
					$course = $this->courseController->getCourse($booking->getBookingForm()->getCourseId());
					$this->registry->getInstance(PaymentHandler::class)->getAndUpdateTransactionStatus($booking->getTransaction()->getId());

					$booking = $bookingDB->getBooking($bookingUUID);
					$bookingDB->removePasswordBooking($bookingUUID);
					in_array($booking->getTransaction()->getStatus(), [TransactionStatus::Payed, TransactionStatus::Saved]) ?
						$this->bookingFormPostService->routeSuccessFulBooking($booking, $course, $bookingUUID) :
						$this->bookingFormPostService->routeUnsuccessfulBooking($booking, $course, $bookingUUID);
				}
			} catch ( InjectionImpossibleException|InvalidResponseException|CourseNotFoundException ) {
			}
		}

		$parser = $this->getNewParser();
		$parser->setData('check-name', PostEntities::BOOKING_FORM);
		$parser->addStylesheet($this->getStylePath());
		$formSettings = $this->formSettings;

		$parser->injectAttribute(
			$this->getRecursiveVersionOfAttribute(SelectableDataInputFieldTag::FIELD_CLASS_ATTRIBUTE),
			BookingFormFieldEnum::class
		);
		$parser->injectAttribute(
			SelectableDataInputFieldTag::FIELD_CLASS_ATTRIBUTE,
			BookingFormFieldEnum::class
		);

		$parser->setData('formTitle', $formSettings->getBookingFormTitle());
		$parser->setData('formNonce', UUIDGenerator::generateUUIDv4OrRandom());

		$successMessage = $this->bookingFormPostService->getSuccessMessage();
		if ($successMessage !== null){
			$parser->setUnsafeData('success-message', $successMessage);
			$parser->setCondition('has-message', true);
			if ( !($this->bookingFormPostService->getBookingSuccess() ?? false) ){
				$parser->setUnsafeData('success-message-type', 'data-template="warningBlock"');
			}
		}

		$dataHandler = $this->dataHandler;
		if ($dataHandler->isPostDataSet())
			$previousForm = $dataHandler->getPostField(PostEntities::BOOKING_FORM);
			$courseId = isset($previousForm) && is_array($previousForm) && is_int($previousForm[BookingFormFieldEnum::COURSE_ID] ?? null) ? $previousForm[BookingFormFieldEnum::COURSE_ID] : null;
			$courseId = $courseId ?? $dataHandler->getPostField( GeneralTermEnum::COURSE_ID );
		if (!isset($courseId))
			$courseId = $this->urlHandler->getUrlQueryField($this->pluginData->getShortPrefix() . GeneralTermEnum::COURSE_ID_URL_QUERY);

		if (!isset($courseId)){
			$parser->setData('error-message', 'Geen cursus geselecteerd');
			return $parser->parse($this->getErrorTemplate());
		}

		$parser->injectAttribute(
			self::RECURSIVE_PREFIX . 'course-id',
			$courseId
		);

		$errors = $this->bookingFormPostService->getError();

		try {
			$course = $this->courseController->getCourse($courseId, true);
			if ($errors instanceof InvalidResponseException || $errors instanceof CourseNotFoundException){
				throw $errors;
			}
		} catch ( InvalidResponseException $e ) {
			$parser->setData('error-message', 'Iets is mis gegaan');
			$parser->setData('error-response-message', 'fout code: ' . $e->getMessage());
			return $parser->parse($this->getErrorTemplate());
		} catch ( CourseNotFoundException ) {
			$parser->setData('error-message', 'Geselecteerde cursus is niet gevonden');
			return $parser->parse($this->getErrorTemplate());
		}

		if ($errors instanceof CourseFullException || $course->getUsersData()->getAvailableSpots($this->includeOptionsAvailability) <= 0) {
			$parser->setData( 'error-message', 'Cursus is vol, daarom is aanmelden niet meer mogelijk' );

			return $parser->parse( $this->getErrorTemplate());
		}

		if ( !$this->formSettings->isStartedCourseBookable() && $course->hasPastDayParts($this->generalSettings->isELearningCountsAsStart())) {
			$parser->setData( 'error-message', 'Cursus is al gestart, daarom is aanmelden niet meer mogelijk' );

			return $parser->parse( $this->getErrorTemplate());
		}

		if ($this->paymentSettings->isPaymentPossible()){
			$parser->setData('paymentInfo', $this->paymentSettings->getPaymentNotice());
			$parser->setCondition('paymentPossible', true);
			$parser->setCondition('paymentNotLive', !$this->paymentSettings->isPaymentLive());
		}

		$parser->setCondition('showVoucher', $formSettings->isAllowVouchers());
		$parser->setCondition('showMaterials', $formSettings->getMaterialSettings()->isAskMaterialsBookingForm() && $this->courseController->courseHasMaterials($courseId));
		$parser->setCondition('showCompanyOptions', !$course->isHasStap() && !isset($this->attributes["company_id"]) && $formSettings->getCompanySettings()->isAllowCompanies());
		$parser->setCondition('showAttributes', count($course->getAttributes()) > 0 && $formSettings->isAskApiAttributes());
		$parser->setCondition('showTermsAndConditions', $formSettings->getStudentSettings()->isTermsAndConditionsRequired());
		$parser->setCondition('showDayPartSelection', $course->getDayPartDisplayType() !== DayPartDisplayTypes::AllSelectedImmutable);
		$parser->setCondition('addCompanyId', isset($this->attributes["company_id"]));

		$parser->setData('courseId', $courseId);
		$parser->setData('companyId', $this->attributes["company_id"] ?? null);
		$parser->setData('showPricesDayParts', $course->isPriceFromDayParts() ? 'data-show-prices' : null);
		$parser->setData('courseName', $course->getName());
		$parser->setData('courseCode', $course->getCode());
		$firstDayPart = $course->getEarliestDayPart($this->generalSettings->isELearningCountsAsStart());
		$firstDayPart ?
			$parser->setData( 'courseStartDate', $firstDayPart->getStartTime()->format("d/m/Y")) :
			$parser->setData( 'courseStartDate', "-");

		$parser->setData('materialsTitle', $formSettings->getMaterialSettings()->getMaterialsFormTitle());
		$parser->setUnsafeData('materialsDescription', $formSettings->getMaterialSettings()->getMaterialsFormDescription());
		$parser->setData('termsAndConditionsURL', $formSettings->getStudentSettings()->getTermsAndConditionsUrl());
		$showCompanyDetails = $this->dataHandler->getPostField(PostEntities::BOOKING_FORM)[BookingFormFieldEnum::AS_COMPANY] ?? $formSettings->getCompanySettings()->isAsCompanyDefault();
		$parser->setData('displayCompanyDetails', $showCompanyDetails ? 'block' : 'none');
		$parser->setData('companyDefault', $formSettings->getCompanySettings()->isAsCompanyDefault() ? '1' : '0');

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