<?php

namespace Planaday\Html\Tags\Mail\BookingMail;

use ArrayAccess;
use Countable;
use DateTime;
use DateTimeZone;
use Planaday\Config\Booking\Submission\Mail\MailSettings;
use Planaday\Config\Course\General\GeneralSettings;
use Planaday\Config\Payment\PaymentSettings;
use Planaday\Entities\Booking\DTO\Booking;
use Planaday\Entities\Booking\DTO\BookingStudent;
use Planaday\Entities\Booking\DTO\Transaction;
use Planaday\Entities\Booking\Enum\BookingStatus;
use Planaday\Entities\Booking\Enum\TransactionStatus;
use Planaday\Entities\Course\DTO\Course;
use Planaday\Html\Tags\Tag;
use Planaday\Payment\Interfaces\PaymentHandler;
use Planaday\Platform\PlatformAbstraction\PlatformConnector;
use Planaday\Platform\PlatformAbstraction\UrlHandler;
use Planaday\Utility\DateAndTimeUtility;
use Planaday\Utility\DependencyInjection\Container;
use Planaday\Utility\DependencyInjection\InjectionImpossibleException;
use Traversable;

class BookingMail extends Tag {

	const TAG = 'mail';
	const DEFAULT_TEMPLATE = 'studentMail';
	const BOOKING_CONTEXT_INDEX = 'booking';
	const COURSE_CONTEXT_INDEX = 'course';
	const MAIL_TEMPLATE_CONTEXT_INDEX = 'mail-template';
	const STUDENT_CONTEXT_INDEX = 'current-student';

	protected DateAndTimeUtility $dateAndTimeUtility;
	protected string $platform;
	protected PaymentHandler $paymentProvider;
	protected UrlHandler $urlHandler;
	protected PaymentSettings $paymentSettings;
	protected MailSettings $mailSettings;
	private GeneralSettings $generalSettings;

	/**
	 * @param Container $registry
	 *
	 * @throws InjectionImpossibleException
	 */
	public function __construct(Container $registry) {
		$this->dateAndTimeUtility = $registry->getInstance(DateAndTimeUtility::class);
		$this->platform = $registry->getInstance(PlatformConnector::class)->getPlatformName();
		$this->paymentProvider = $registry->getInstance(PaymentHandler::class);
		$this->mailSettings = $registry->getInstance(MailSettings::class);
		$this->paymentSettings = $registry->getInstance(PaymentSettings::class);
		$this->urlHandler = $registry->getInstance(UrlHandler::class);
		$this->generalSettings = $registry->getInstance(GeneralSettings::class);
		parent::__construct(__DIR__, self::DEFAULT_TEMPLATE, $registry);
	}

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

		$booking = $this->context[self::BOOKING_CONTEXT_INDEX] ?? null;
		$course = $this->context[self::COURSE_CONTEXT_INDEX] ?? null;

		if (isset($course, $booking) &&
		    $course instanceof Course &&
		    $booking instanceof Booking
		){
			$template = $this->context[self::MAIL_TEMPLATE_CONTEXT_INDEX] ?? null;
			if (isset($template) && is_string($template)){
				$template = $this->convertLegacyTemplate($template);
			}

			$student = $this->context[self::STUDENT_CONTEXT_INDEX] ?? null;
			if (isset($student) && $student instanceof BookingStudent){
				$firstName = $student->getFirstName();
				$lastName = $student->getLastName();
				$prefix = $student->getPrefix();
				$initials = $student->getInitials();

				$parser->setData('first-name', $firstName);
				$parser->setData('last-name', $lastName);
				$parser->setData('full-name', implode(' ', [$firstName, $initials, $prefix, $lastName]));
			}

			$startDate = $this->dateAndTimeUtility->getReadableDate(
				$course->getEarliestDayPart(
					$this->generalSettings->isELearningCountsAsStart()
				)?->getStartTime() ??
				(new DateTime())->setTimezone(new DateTimeZone("Europe/Amsterdam"))
			);

			$parser->setUnsafeData('students', $this->getStudentsBlock($booking->getBookingForm()->getStudents()));
			$parser->setCondition('showStudentMailWarning', $this->mailSettings->isStudentToggle() && count($booking->getBookingForm()->getStudents()) == 1);

			$parser->setData('course-name', $course->getName());
			$parser->setData('course-code', $course->getCode());
			$parser->setData('website', $this->urlHandler->getWebsiteName());
			$parser->setData('course-start-date', $startDate);
			$parser->setData('platform', $this->platform);
			$parser->setData('booking-id', $booking->getBookingId());
			$parser->setCondition('mailSuccessful', $booking->getBookingStatus() !== BookingStatus::Failed);
			$parser->setCondition('studentIsMailed', ($booking->getBookingForm()->getStudents()[0] ?? false) && $booking->getBookingForm()->getStudents()[0]->getEmail() != '' && $booking->getBookingStatus() !== BookingStatus::Failed);

			$company = $booking->getBookingForm()->getCompany();
			if ($company !== null){
				$parser->setData('company-name', $company->getName());
				$parser->setData('company-mail', $company->getEmail());
				$parser->setCondition('companyShown', true);
			}

			$transaction = $booking->getTransaction();
			if ($transaction !== null){
				if (($this->attributes[self::TEMPLATE_ATTRIBUTE] ?? self::DEFAULT_TEMPLATE) != 'studentMail')
					$parser->setUnsafeData('payment', $this->getTransactionBlock($booking, $transaction));
				$parser->setData('transaction-total', $transaction->getTotalCost());
				$parser->setData('transaction-id', $transaction->getId());
				$payed = $transaction->getStatus() == TransactionStatus::Payed || $transaction->getStatus() == TransactionStatus::Saved;
				$parser->setData('transaction-success', $payed ? 'Ja' : 'Nee' );
			}

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

		$this->logError("Invalid context for mail tag");
		return '';
	}

	/**
	 * @param ArrayAccess<BookingStudent>&Traversable<BookingStudent>&Countable $students
	 *
	 * @return string
	 */
	private function getStudentsBlock( ArrayAccess&Traversable&Countable $students):string {
		$html = '';
		$studentCount = count($students);

		$i = 0;
		foreach ($students as $student) {
			$parser = $this->getNewParser();
			$parser->setData('first-name', $student->getFirstName());
			$parser->setData('last-name', $student->getLastName());
			$parser->setData('student-email', $student->getEmail());
			$parser->setData('student-number',  $studentCount > 1 ? ' ' . ($i + 1) : '');
			$html .= $parser->parse( $this->getTemplate('Student'));
			$i++;
		}

		return $html;
	}

	private function getTransactionBlock(Booking $booking, Transaction $transaction):string {
		$parser = $this->getNewParser();

		$parser->setData('booking-id', $booking->getBookingId());
		$parser->setData('payment-info-url', $this->paymentProvider->getDetailsLink($transaction->getId()));
		$parser->setData('transaction-id', $transaction->getId());
		$parser->setData('transaction-total', $transaction->getTotalCost());
		$parser->setData('transaction-method', $transaction->getMethod());

		$parser->setCondition('paymentSuccessful', $transaction->getStatus() == TransactionStatus::Payed || $transaction->getStatus() == TransactionStatus::Saved);
		$parser->setCondition('padPaymentSuccessful', $transaction->getStatus() == TransactionStatus::Saved);
		$parser->setCondition('testPayment', $this->paymentSettings->isPaymentLive() === false);

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

	protected function convertLegacyTemplate(string $template):string {
		return str_replace([
			"{cursus}",
			"{voornaam}",
			"{achternaam}",
			"{naam}",
			"{website}",
			"{startdatum}",
			"{padboekingid}",
			"{idealtransactieid}",
			"{bedrag}",
			"{betaald}",
			"{studenteninfo}",
			"{betaalinfo}",
			"{bedrijfsnaam}"
		], [
			"{{pad-course-name}}",
			"{{pad-first-name}}",
			"{{pad-last-name}}",
			"{{pad-full-name}}",
			"{{pad-website}}",
			"{{pad-course-start-date}}",
			"{{pad-booking-id}}",
			"{{pad-transaction-id}}",
			"{{pad-transaction-total}}",
			"{{pad-transaction-success}}",
			"{{pad-students}}",
			"{{pad-payment}}",
			"{{pad-company-name}}"
		], $template);
	}
}