<?php

namespace Planaday\Config\OptionGroups\General;

use Planaday\Config\OptionGroups\General\Api\ApiOptionsValidator;
use Planaday\Config\OptionGroups\General\Debug\DebugOptionsValidator;
use Planaday\Config\OptionGroups\General\Price\PriceOptionsValidator;
use Planaday\Platform\PlatformAbstraction\LocalizationController;
use Planaday\Utility\DataFilters\InvalidFieldsException;
use Planaday\Utility\DataFilters\TypeValidator;
use Planaday\Utility\Debug\Log\Logging;

class GeneralOptionsValidator {
	use Logging;

	/** @var ApiOptionsValidator */
	private $apiValidator;

	/** @var DebugOptionsValidator */
	private $debugOptionsValidator;

	/** @var PriceOptionsValidator */
	private $priceOptionsValidator;

	/** @var TypeValidator */
	private $typeValidator;

	/** @var LocalizationController */
	private $localizationController;

	public function __construct(
		TypeValidator $typeValidator,
		LocalizationController $translator,
		ApiOptionsValidator $apiValidator,
		DebugOptionsValidator $debugOptionsValidator,
		PriceOptionsValidator $priceOptionsValidator
	) {
		$this->apiValidator           = $apiValidator;
		$this->debugOptionsValidator  = $debugOptionsValidator;
		$this->priceOptionsValidator  = $priceOptionsValidator;
		$this->typeValidator          = $typeValidator;
		$this->localizationController = $translator;
	}

	/**
	 * @param array $data
	 * @param array|null $output if valid, clean data is returned here. if not, errors will be returned here
	 *
	 * @return bool true if valid, false if not
	 */
	public function validate( array $data, ?array &$output ): bool {
		$errors = [];
		$tr     = $this->localizationController;
		$this->logInfo( 'Validating general options' );

		try {
			$data = $this->getSafeData( $data );
		} catch ( InvalidFieldsException $e ) {
			foreach ( $e->getInvalidFields() as $field => $fieldException ) {
				$this->logError( 'Invalid field: ' . $field . ' with error: ' . $fieldException->getMessage() );
				$errors[ $field ] = $tr->translate(
					'Het ' . strtolower( $field ) . ' veld bij de algemene opties is met ongeldige data ingevuld.'
				);
			}

			$output = $errors;

			return false;
		}

		if ( ! $this->apiValidator->validate( $data[ GeneralOptionsEnum::API_SETTINGS ] ?? [], $apiOptions ) ) {
			$errors[ GeneralOptionsEnum::API_SETTINGS . '-isValid' ] = $tr->translate( 'De API instellingen zijn niet correct ingevuld.' );
			$errors[ GeneralOptionsEnum::API_SETTINGS ]              = $apiOptions;
		} else {
			$data[ GeneralOptionsEnum::API_SETTINGS ] = $apiOptions;
		}

		if ( ! $this->debugOptionsValidator->validate( $data[ GeneralOptionsEnum::DEBUG ] ?? [], $debugOutput ) ) {
			$errors[ GeneralOptionsEnum::DEBUG . '-isValid' ] = $tr->translate( 'De Debug instellingen zijn niet correct ingevuld.' );
			$errors[ GeneralOptionsEnum::DEBUG ]              = $debugOutput;
		} else {
			$data[ GeneralOptionsEnum::DEBUG ] = $debugOutput;
		}

		if ( ! $this->priceOptionsValidator->validate( $data[ GeneralOptionsEnum::PRICE_OPTIONS ] ?? [], $priceOutput ) ) {
			$errors[ GeneralOptionsEnum::PRICE_OPTIONS . '-isValid' ] = $tr->translate( 'De prijs instellingen zijn niet correct ingevuld.' );
			$errors[ GeneralOptionsEnum::PRICE_OPTIONS ]              = $priceOutput;
		} else {
			$data[ GeneralOptionsEnum::PRICE_OPTIONS ] = $priceOutput;
		}

		if ( count( $errors ) > 0 ) {
			$output = $errors;
			$this->logWarning("data is not valid", $errors);
			return false;
		}

		$output = $data;
		return true;
	}

	/**
	 * @param array $data
	 *
	 * @return array
	 * @throws InvalidFieldsException
	 */
	private function getSafeData( array $data ): array {
		$tv = $this->typeValidator;

		$array = [
			GeneralOptionsEnum::API_SETTINGS,
			GeneralOptionsEnum::DEBUG,
			GeneralOptionsEnum::PRICE_OPTIONS,
		];

		return $tv->getSafeData( $data, [], $array );
	}
}