<?php

namespace Planaday\Entities\Booking\Form;

use Planaday\Config\BasicEnumMappedSetting;
use Planaday\Config\EnumMappedSettings;
use Planaday\Config\FeatureToggles\FeatureToggleSettings;
use Planaday\Config\FormGroupable;
use Planaday\Config\Payment\PaymentSettings;
use Planaday\Config\SettingsLoader;
use Planaday\Config\SettingsWithForm;
use Planaday\Entities\Booking\Form\Address\AddressSettings;
use Planaday\Entities\Booking\Form\Address\AddressSettingsEnum;
use Planaday\Entities\Booking\Form\Company\CompanySettings;
use Planaday\Entities\Booking\Form\Company\CompanySettingsEnum;
use Planaday\Entities\Booking\Form\DayParts\DayPartsSettings;
use Planaday\Entities\Booking\Form\DayParts\DayPartsSettingsEnum;
use Planaday\Entities\Booking\Form\Materials\MaterialSettings;
use Planaday\Entities\Booking\Form\Materials\MaterialSettingsEnum;
use Planaday\Entities\Booking\Form\Students\StudentSettings;
use Planaday\Entities\Booking\Form\Students\StudentSettingsEnum;
use Planaday\Platform\PlatformAbstraction\LocalizationController;
use Planaday\Utility\DependencyInjection\Attributes\Scoped;
use Planaday\Utility\FormBuilder\Conditions\InputValueCondition;
use Planaday\Utility\FormBuilder\InputFields\BoolInput;
use Planaday\Utility\FormBuilder\InputFields\NumberInput;
use Planaday\Utility\FormBuilder\InputFields\StringInput;
use Planaday\Utility\FormBuilder\LayoutItems\Text;
use Planaday\Utility\FormBuilder\Structures\BasicGroup;
use Planaday\Utility\FormBuilder\Structures\CollapsibleGroup;
use Planaday\Utility\FormBuilder\Structures\FullScreenPopup;
use Planaday\Utility\FormBuilder\Validators\RegexValidator;
use Planaday\Utility\FormBuilder\Validators\Required;
use Planaday\Utility\RegexUtility;

#[Scoped]
class BookingFormSettings implements EnumMappedSettings, SettingsWithForm {
	use FormGroupable;
	use BasicEnumMappedSetting;

	protected string $bookingFormTitle = 'Cursus meteen zelf boeken';
	protected bool $askApiAttributes = false;
	protected bool $startedCourseBookable = false;
	protected bool $mustAcceptTermsAndConditions = false;
	protected ?string $termsAndConditionsUrl = null;
	protected bool $askVoucher = false;
	protected int $setCompanyId = 0;
	protected bool $allowInvoicePaymentCompany = false;

	public function __construct(
		protected LocalizationController $translator,
		SettingsLoader $settingsLoader,
		protected AddressSettings $addressSettings,
		protected CompanySettings $companySettings,
		protected MaterialSettings $materialSettings,
		protected StudentSettings $studentSettings,
		protected DayPartsSettings $dayPartsSettings,
		protected FeatureToggleSettings $featureToggleSettings,
		protected PaymentSettings $paymentSettings
	) {
		$settingsLoader->reloadData($this, BookingFormSettingsEnum::class);
	}

	protected function createFormGroup(): FullScreenPopup {
		$t = function ( string $string ) {
			return $this->translator->translate( $string );
		};

		$overrideCompanyId = ( new NumberInput() )
			->setIndex( BookingFormSettingsEnum::CompanyId->value )
			->setName( $t( "Bedrijf ID" ) )
			->setDescription($t("Het ID van het bedrijf waar de inschrijvingen aan " .
			                    "gekoppeld moeten worden. (0 = niet overschrijven)"))
			->setDefaultValue( $this->setCompanyId )
			->addSetCallback( function ( $value ) {
				$this->setCompanyId = $value ?? $this->setCompanyId;
			})
			->setMin(0)
			->setStep(1);

		return ( new FullScreenPopup() )
			->setIndex( BookingFormSettingsEnum::class )
			->setButtonTitle( $t( "Formulier instellen" ))
			->setCloseButtonText( $t( "Sluiten" ))
			->addContents(
				(new Text($this->translator->translate("Alle wijzigingen worden automatisch " .
				                                       "bijgehouden en gelden alleen voor dit block. Sluit dit venster " .
				                                       "en sla de pagina op om de wijzigingen te bevestigen.")))
					->addClasses("pad-popup-notice"),
				( new StringInput() )
					->setIndex( BookingFormSettingsEnum::Title->value )
					->setName( $t( "Titel boeking formulier" ) )
					->setDescription($t("De titel van het boeking formulier."))
					->setDefaultValue( $this->bookingFormTitle )
					->setPlaceholder( $t( "Cursus boeken en meteen zelf boeken" ) )
					->addSetCallback( function ( $value ) {
						$this->bookingFormTitle = $value ?? $this->bookingFormTitle;
					})
					->addValidator(
						new Required( $t( "Titel is verplicht" ) )
					),
				( new BoolInput() )
					->setIndex( BookingFormSettingsEnum::AllowBookingOfStartedCourse->value )
					->setName( $t( "Gestarte cursus boekbaar" ) )
					->setDescription($t("Kan nog inschrijven op een cursus die al gestart is?"))
					->setDefaultValue( $this->startedCourseBookable )
					->addSetCallback( function ( $value ) {
						$this->startedCourseBookable = $value ?? $this->startedCourseBookable;
					}),
				$this->dayPartsSettings->getFormGroup(),
				$this->materialSettings->getFormGroup(),
				$this->addressSettings->getFormGroup(),
				( new BasicGroup() )
					->addContents(
						$this->companySettings->getFormGroup(),
					)->addConditions(
						( new InputValueCondition( $overrideCompanyId ) )->equals()->value( 0)
					),
				$this->studentSettings->getFormGroup(),
				( new CollapsibleGroup() )
					->setHeader($t("Algemene voorwaarden"))
					->startCollapsed()
					->setDescription($t("De algemene voorwaarden voor het boekingsformulier."))
					->addContents(
						$mustAcceptTerms = ( new BoolInput() )
							->setIndex( BookingFormSettingsEnum::MustAcceptTermsAndConditions->value )
							->setName( $t( "Algemene voorwaarden accepteren" ) )
							->setDescription($t("Moet de gebruiker van het formulier de algemene voorwaarden accepteren?"))
							->setDefaultValue( $this->mustAcceptTermsAndConditions )
							->addSetCallback( function ( $value ) {
								$this->mustAcceptTermsAndConditions = $value ?? $this->mustAcceptTermsAndConditions;
							}),
						(new BasicGroup())
							->addContents(
								( new StringInput() )
									->setIndex( BookingFormSettingsEnum::TermsAndConditions->value )
									->setName( $t( "Algemene voorwaarden URL" ) )
									->setDescription($t("De URL van de algemene voorwaarden."))
									->setDefaultValue( $this->termsAndConditionsUrl )
									->addSetCallback( function ( $value ) {
										$this->termsAndConditionsUrl = $value ?? $this->termsAndConditionsUrl;
									})->addValidator(
										new Required( $t( "Algemene voorwaarden URL is verplicht als deze geaccepteerd moeten worden" ) ),
										new RegexValidator("url", RegexUtility::SIMPLE_URL_REGEX, $t( "Deze URL is niet geldig" ) )
									)
							)->addConditions(
								( new InputValueCondition( $mustAcceptTerms ) )->equals()->value( true)
							)
					),
				(new BoolInput())
					->setIndex( BookingFormSettingsEnum::AskApiAttributes->value )
					->setName( $t( "API attributen vragen?" ) )
					->setDescription($t("Moeten de api attributen gevraagd worden?"))
					->setDefaultValue( $this->askApiAttributes )
					->addSetCallback( function ( $value ) {
						$this->askApiAttributes = $value ?? $this->askApiAttributes;
					}),
				(new BoolInput())
					->setIndex( BookingFormSettingsEnum::AskVoucher->value )
					->setName( $t( "Kortingscode vragen?" ) )
					->setDescription($t("Kan de gebruiker van het formulier een kortingscode invoeren?"))
					->setDefaultValue( $this->askVoucher )
					->addSetCallback( function ( $value ) {
						$this->askVoucher = $value ?? $this->askVoucher;
					}),
				...($this->paymentSettings->isAllowCompanyInvoice() ? [(new BoolInput())
					->setIndex( BookingFormSettingsEnum::GivePaymentOptionsCompany->value )
					->setName( $t( "Betalen met factuur optie?" ) )
					->setDescription($t("Krijgen bedrijven de optie om te betalen met een factuur?"))
					->setDefaultValue( $this->askVoucher )
					->addSetCallback( function ( $value ) {
						$this->askVoucher = $value ?? $this->askVoucher;
					})] : []),
				...[(new CollapsibleGroup())
					->startCollapsed()
					->setHeader($t("Bedrijf overschrijven"))
					->setDescription("")
					->addContents(
						(new Text($t("LET OP: dit wordt niet aangeraden om te gebruiken, gebruik dit alleen als u " .
						             "door planaday bent aangeraden om dit te doen.")))->addClasses("pad-warning"),
						$overrideCompanyId,
					)]
			);
	}

	/**
	 * @return array{values:mixed[], subGroups:array[], subGroupAliases:string[]}
	 */
	public function getEnumMapping(): array {
		return [
			"values"          => [
				BookingFormSettingsEnum::Title->value                        => &$this->bookingFormTitle,
				BookingFormSettingsEnum::AllowBookingOfStartedCourse->value  => &$this->startedCourseBookable,
				BookingFormSettingsEnum::AskApiAttributes->value             => &$this->askApiAttributes,
				BookingFormSettingsEnum::MustAcceptTermsAndConditions->value => &$this->mustAcceptTermsAndConditions,
				BookingFormSettingsEnum::TermsAndConditions->value           => &$this->termsAndConditionsUrl,
				BookingFormSettingsEnum::AskVoucher->value                   => &$this->askVoucher,
				BookingFormSettingsEnum::CompanyId->value                    => &$this->setCompanyId,
				BookingFormSettingsEnum::GivePaymentOptionsCompany->value     => &$this->allowInvoicePaymentCompany,
			],
			"subGroups"       => [
				BookingFormSettingsEnum::Address->value => $this->addressSettings->getEnumMapping(),
				BookingFormSettingsEnum::Company->value => $this->companySettings->getEnumMapping(),
				BookingFormSettingsEnum::Materials->value => $this->materialSettings->getEnumMapping(),
				BookingFormSettingsEnum::Students->value => $this->studentSettings->getEnumMapping(),
				BookingFormSettingsEnum::DayParts->value => $this->dayPartsSettings->getEnumMapping(),
			],
			"subGroupAliases" => [
				AddressSettingsEnum::class => BookingFormSettingsEnum::Address->value,
				CompanySettingsEnum::class => BookingFormSettingsEnum::Company->value,
				MaterialSettingsEnum::class => BookingFormSettingsEnum::Materials->value,
				StudentSettingsEnum::class => BookingFormSettingsEnum::Students->value,
				DayPartsSettingsEnum::class => BookingFormSettingsEnum::DayParts->value,
			]
		];
	}

	public function getBookingFormTitle(): string {
		return $this->bookingFormTitle;
	}

	public function isAskApiAttributes(): bool {
		return $this->askApiAttributes;
	}

	public function isStartedCourseBookable(): bool {
		return $this->startedCourseBookable;
	}

	public function isMustAcceptTermsAndConditions(): bool {
		return $this->mustAcceptTermsAndConditions;
	}

	public function getTermsAndConditionsUrl(): ?string {
		return $this->termsAndConditionsUrl;
	}

	public function isAskVoucher(): bool {
		return $this->askVoucher;
	}

	public function isGivePaymentOptionsCompany(): bool {
		return $this->allowInvoicePaymentCompany;
	}

	public function getCompanyId(): int {
		return $this->setCompanyId;
	}
}