<?php

namespace Planaday\Entities\Voucher;

use Planaday\Api\ApiException\InvalidResponseException;
use Planaday\Config\Booking\Voucher\VoucherSettings;
use Planaday\Config\General\Price\PriceSettings;
use Planaday\Entities\Course\CourseController;
use Planaday\Entities\Course\Exception\CourseNotFoundException;
use Planaday\Entities\Voucher\DTO\Voucher;
use Planaday\Entities\Voucher\Exception\VoucherInvalidException;
use Planaday\Entities\Voucher\Exception\VoucherNotFoundException;
use Planaday\Platform\PlatformAbstraction\LocalizationController;
use Planaday\Utility\DataFilters\InvalidException;
use Planaday\Utility\DataFilters\TypeValidator;
use Planaday\Utility\Endpoints\ApiController;
use Planaday\Utility\Endpoints\RequestMethod;
use Planaday\Utility\Endpoints\ApiEndpoint;
use Planaday\Utility\Endpoints\RequestData;
use Planaday\Utility\FormBuilder\SubmitStrategies\RestResponses\Message;
use Planaday\Utility\FormBuilder\SubmitStrategies\RestResponses\ResponseStatus;

#[ApiController(1, 'voucher')]
class VoucherPluginApi {

	public function __construct(
		protected LocalizationController $translator,
		protected TypeValidator $typeValidator,
		protected VoucherApi $voucherApi,
		protected CourseController $courseController,
		protected PriceSettings $priceSettings,
		protected VoucherSettings $voucherSettings
	) {}

	#[ApiEndpoint("check", RequestMethod::POST)]
	#[ApiEndpoint("check/course/(?P<courseId>[0-9]+)/", RequestMethod::POST)]
	public function checkVoucher(RequestData $data): Message {
		$t = function ($string) {return $this->translator->translate($string);};
		$courseId = $data->getUrlParams()['courseId'] ?? null;

		try{
			$code = trim($this->typeValidator->str($data->getBody()['voucher'] ?? ''));
		} catch (InvalidException){
			return ( new Message() )
				->setStatus(ResponseStatus::Failed)
				->setMessage($t('Deze kortingscode is niet een geldige code.'));
		}

		if ( empty($code) ){
			return ( new Message() )
				->setStatus(ResponseStatus::Failed)
				->setMessage($t('Kortingscode is niet ingevuld.'));
		}

		try{
			$voucher = $this->voucherApi->getVoucher($code);
		} catch ( InvalidResponseException $e ) {
			return ( new Message() )
				->setStatus( ResponseStatus::ServerError )
				->setMessage($t('Iets is mis gegaan op de server, probeer later opnieuw. Error code: ') . $e->getCode());
		} catch ( VoucherNotFoundException ) {
			return ( new Message() )
				->setStatus( ResponseStatus::Failed )
				->setMessage($t('Deze kortingscode is niet bekend.'));
		} catch ( VoucherInvalidException ) {
			return ( new Message() )
				->setStatus( ResponseStatus::Failed )
				->setMessage($t('Deze kortingscode is niet (meer) geldig.'));
		}

		if ( $voucher->isForCourseTemplate() ){
			if ( empty($courseId) ) {
				return ( new Message() )
					->setStatus(ResponseStatus::Failed)
					->setMessage($t('Cursus waarop code moet worden uitgevoerd is niet ingevuld.'));
			}

			try{
				$course = $this->courseController->getCourse($courseId);
			} catch ( InvalidResponseException $e ) {
				return ( new Message() )
					->setStatus( ResponseStatus::ServerError )
					->setMessage($t('Iets is mis gegaan op de server, probeer later opnieuw. Error code: ') . $e->getCode());
			} catch ( CourseNotFoundException ) {
				return ( new Message() )
					->setStatus( ResponseStatus::Failed )
					->setMessage($t('Cursus is niet bekend.'));
			}

			if ($voucher->getCourseTemplate() !== $course->getTemplateId()){
				return ( new Message() )
					->setStatus( ResponseStatus::Failed )
					->setMessage($t('Deze kortingscode is niet geldig voor deze cursus.'));
			}
		}

		return ( new Message() )
			->setStatus(ResponseStatus::Success)
			->setMessage($this->constructVoucherResponse($voucher));
	}

	protected function constructVoucherResponse(Voucher $voucher): string {
		$t = function ($string) {return $this->translator->translate($string);};

		$output = '';
		switch ($voucher->getType()) {
			case VoucherType::Amount:
				$string = $t('Kortingscode %s zal succesvol toegepast worden voor tot %s euro korting op de cursus');
				$output .= sprintf($string, $voucher->getCode(), number_format($voucher->getAmount(), 2, $this->priceSettings->isUsePointsForDecimals() ? '.' : ',', ''));
				break;
			case VoucherType::Percentage:
			default:
				$string = $t( 'Kortingscode %s zal succesvol toegepast worden voor %s procent korting op de cursus');
				$output.= sprintf($string, $voucher->getCode(), number_format($voucher->getAmount(), 0, '', ''));
		}

		if (
			$voucher->getValidUntil() !== null &&
			$this->voucherSettings->isShowVoucherAlmostExpiredMessage() &&
			$voucher->getValidUntil()->getTimestamp() <= strtotime('+' . $this->voucherSettings->getVoucherAlmostExpiredThreshold() . ' day')
		){
			$output .= "\n" . $this->voucherSettings->getVoucherAlmostExpiredMessage();
		}

		if (
			($voucher->getAvailable() ?? 0) > 0 &&
			$this->voucherSettings->isShowVoucherAlmostUsedUpMessage() &&
			$voucher->getAvailable() <= $this->voucherSettings->getVoucherAlmostUsedUpThreshold()
		){
			$output .= "\n" . $this->voucherSettings->getVoucherAlmostUsedUpMessage();
		}

		return $output;
	}
}