<?php

namespace Planaday\Config\General\Api;

use Planaday\Config\BasicEnumMappedSetting;
use Planaday\Config\BasicSettingsLog;
use Planaday\Config\EnumMappedSettings;
use Planaday\Config\FormGroupable;
use Planaday\Config\SettingsLoader;
use Planaday\Config\SettingsWithForm;
use Planaday\Config\SettingsWithUsageLog;
use Planaday\Platform\PlatformAbstraction\LocalizationController;
use Planaday\Utility\Debug\Log\Logging;
use Planaday\Utility\DependencyInjection\Attributes\Scoped;
use Planaday\Utility\FormBuilder\InputFields\NumberInput;
use Planaday\Utility\FormBuilder\InputFields\StringInput;
use Planaday\Utility\FormBuilder\Structures\BasicGroup;
use Planaday\Utility\FormBuilder\Validators\RegexValidator;
use Planaday\Utility\FormBuilder\Validators\Required;

#[Scoped]
class ApiSettings implements EnumMappedSettings, SettingsWithForm, SettingsWithUsageLog {
	use Logging;
	use FormGroupable;
	use BasicEnumMappedSetting;
	use BasicSettingsLog;

	public const DOMAIN_REGEX = '/^(?:https:\/\/)?([a-zA-Z0-9\-$_+!*()\',]+)(?:\.api)?(?:\.planaday)?(\.[a-zA-Z]{2,3})?\/?$/';

	private ?string $domain = null;
	private ?string $apiKey = null;
	private int $refreshIntervalCourses = 12;
	private int $refreshIntervalDayParts = 24;
	private int $refreshIntervalLocations = 24;
	private int $refreshSizeCourses = 12;

	public function __construct(
		protected LocalizationController $translator,
		protected SettingsLoader $settingsDatabase
	) {
		$this->settingsDatabase->reloadData( $this, ApiOptionsEnum::class );
	}

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

		$required = new Required($t('Dit veld is verplicht'));

		return ( new BasicGroup() )
			->setIndex( ApiOptionsEnum::class )
			->addContents(
				(new StringInput())
					->setIndex(ApiOptionsEnum::DOMAIN->value)
					->setName($t('Adres van portal'))
					->setDescription($t('Deze vindt u in jouw Planaday bij beheer->koppelingen->publieke api'))
					->setDefaultValue($this->domain)
					->setPlaceholder('https://klantnaam.api.planaday.nl')
					->addSetCallback( function ( $value ) {
						$this->domain = $value;
					})
					->addValidator(
						$required,
						new RegexValidator( 'domainValid', self::DOMAIN_REGEX, $t('Voer een geldig Url in, bijv. "https://klantnaam.api.planaday.nl" of "klantnaam.planaday.nl"'))
					),
				(new StringInput())
					->setIndex(ApiOptionsEnum::API_KEY->value)
					->setName($t('API key'))
					->setDescription($t('Deze genereert u zelf in jouw planaday bij beheer->koppelingen->publieke api'))
					->setDefaultValue($this->apiKey)
					->setPlaceholder('********')
					->addSetCallback( function ( $value ) {
						$this->apiKey = $value;
					})
					->addValidator( $required ),
				(new NumberInput())
					->setIndex(ApiOptionsEnum::REFRESH_INTERVAL_COURSES->value)
					->setName($t('Verversingsinterval cursussen'))
					->setDescription($t('Vul hier in om de hoeveel uur de cursussen ververst moet worden, hoe ' .
					                    'lager de uren, hoe vaker er data opgehaald zal worden. Wij raden 12 uur aan.'))
					->setDefaultValue($this->refreshIntervalCourses)
					->setMin(2)
					->addSetCallback( function ( $value ) {
						$this->refreshIntervalCourses = $value ?? $this->refreshIntervalCourses;
					})
					->addValidator( $required ),
				(new NumberInput())
					->setIndex(ApiOptionsEnum::REFRESH_INTERVAL_DAY_PARTS->value)
					->setName($t('Verversingsinterval dagdelen'))
					->setDescription($t('Vul hier in om de hoeveel uur de bekende dagdelen geupdate moet worden, ' .
					                    'hoe lager de uren, hoe vaker er data opgehaald zal worden. Wij raden 24 uur aan.'))
					->setDefaultValue($this->refreshIntervalDayParts)
					->setMin(2)
					->addSetCallback( function ( $value ) {
						$this->refreshIntervalDayParts = $value ?? $this->refreshIntervalDayParts;
					})
					->addValidator( $required ),
				(new NumberInput())
					->setIndex(ApiOptionsEnum::REFRESH_INTERVAL_LOCATIONS->value)
					->setName($t('Verversingsinterval locaties'))
					->setDescription($t('Vul hier in om de hoeveel uur de bekende locaties geupdate moet worden' .
					                    ', hoe lager de uren, hoe vaker er data opgehaald zal worden. Wij raden 24 uur aan.'))
					->setDefaultValue($this->refreshIntervalLocations)
					->setMin(2)
					->addSetCallback( function ( $value ) {
						$this->refreshIntervalLocations = $value ?? $this->refreshIntervalLocations;
					})
					->addValidator( $required ),
				(new NumberInput())
					->setIndex(ApiOptionsEnum::REFRESH_SIZE_COURSES->value)
					->setName($t('Inlaad Hoeveelheid'))
					->setDescription($t('Cursussen binnen zoveel maanden zullen worden ingeladen. ' .
					                    'Wij raden 12 maanden aan.'))
					->setDefaultValue($this->refreshSizeCourses)
					->setMin(1)
					->addSetCallback( function ( $value ) {
						$this->refreshSizeCourses = $value ?? $this->refreshSizeCourses;
					})
					->addValidator( $required ),
			);
	}

	/**
	 * @return array{values:mixed[], subGroups:array[], subGroupAliases:string[]}
	 */
	public function getEnumMapping(): array {
		return [
			"values"          => [
				ApiOptionsEnum::DOMAIN->value                     => &$this->domain,
				ApiOptionsEnum::API_KEY->value                    => &$this->apiKey,
				ApiOptionsEnum::REFRESH_INTERVAL_COURSES->value   => &$this->refreshIntervalCourses,
				ApiOptionsEnum::REFRESH_INTERVAL_DAY_PARTS->value => &$this->refreshIntervalDayParts,
				ApiOptionsEnum::REFRESH_INTERVAL_LOCATIONS->value => &$this->refreshIntervalLocations,
				ApiOptionsEnum::REFRESH_SIZE_COURSES->value       => &$this->refreshSizeCourses,
			],
			"subGroups"       => [],
			"subGroupAliases" => []
		];
	}

	public function getDomain(): ?string {
		$this->logUse( ApiOptionsEnum::DOMAIN );
		if ( $this->domain === null || $this->domain === 'test' ) {
			return $this->domain;
		}

		$valid = preg_match('@(?:https://)?([a-zA-Z0-9\-$_+!*()\',]+)(?:\.api)?(?:\.planaday)?(\.[a-zA-Z]{2,3})?/?@', $this->domain, $matches, PREG_UNMATCHED_AS_NULL);

		if (!$valid) {
			return null;
		}

		return 'https://' . $matches[1] . '.api.planaday' . ( $matches[2] ?? '.nl');
	}

	public function getApiKey(): ?string {
		$this->logUse( ApiOptionsEnum::API_KEY );
		return $this->apiKey;
	}

	public function getRefreshIntervalCourses(): int {
		$this->logUse( ApiOptionsEnum::REFRESH_INTERVAL_COURSES );
		return $this->refreshIntervalCourses;
	}

	public function getRefreshIntervalDayParts(): int {
		$this->logUse( ApiOptionsEnum::REFRESH_INTERVAL_DAY_PARTS );
		return $this->refreshIntervalDayParts;
	}

	public function getRefreshIntervalLocations(): int {
		$this->logUse( ApiOptionsEnum::REFRESH_INTERVAL_LOCATIONS );
		return $this->refreshIntervalLocations;
	}

	public function getRefreshSizeCourses(): int {
		$this->logUse( ApiOptionsEnum::REFRESH_SIZE_COURSES );
		return $this->refreshSizeCourses;
	}
}