<?php

namespace Planaday\Entities\Booking;

use ArrayAccess;
use Countable;
use Planaday\Api\ApiException\InvalidResponseException;
use Planaday\Config\Payment\PaymentSettings;
use Planaday\Entities\Booking\DTO\BookingForm;
use Planaday\Entities\Booking\DTO\BookingResponse;
use Planaday\Entities\Booking\DTO\ExtraField;
use Planaday\Entities\Booking\DTO\Transaction;
use Planaday\Entities\Booking\Enum\BookingStatus;
use Planaday\Entities\Booking\Enum\TransactionStatus;
use Planaday\Entities\Course\CourseController;
use Planaday\Entities\Course\Exception\CourseNotFoundException;
use Planaday\Utility\DependencyInjection\Container;
use Planaday\Utility\DependencyInjection\InjectionImpossibleException;
use Traversable;

class BookingController {
	public function __construct(
		protected BookingApi $api,
		protected ExtraFieldCache $extraFieldCache,
		protected BookingDatabase $database,
		protected PaymentSettings $paymentSettings,
		protected Container $registry
	) {}

	/**
	 * @param BookingForm $bookingForm
	 *
	 * @return BookingResponse
	 * @throws InvalidResponseException
	 */
	public function doBooking(BookingForm $bookingForm):BookingResponse{
		return $this->api->doBooking($bookingForm);
	}

	/**
	 * @return ArrayAccess<ExtraField<mixed>>&Traversable<ExtraField<mixed>>&Countable
	 * @throws InvalidResponseException
	 */
	public function getExtraFields():ArrayAccess&Traversable&Countable {
		if($this->extraFieldCache->isFilled()){
			return $this->extraFieldCache->get();
		}

		$api = $this->api->getExtraFieldsList();
		$this->extraFieldCache->set($api);
		return $api;
	}

	public function checkAndUpdateBookingTransaction(Transaction $transaction):void {
		$databaseTransaction = $this->database->getTransaction($transaction->getId());

		if ($databaseTransaction === null ||
		    $transaction->getStatus() === TransactionStatus::Pending ||
			$databaseTransaction->getStatus() === TransactionStatus::Failed ||
			$databaseTransaction->getStatus() === TransactionStatus::Payed ) {
			return;
		}

		$booking = $this->database->getBookingByTransaction($transaction->getId());
		if ($booking === null) {
			return;
		}

		if ($transaction->getStatus() === TransactionStatus::Payed) {
			$succes = $this->api->postPaymentDataBooking($booking->getBookingId(), $transaction->getId());

			if ($succes){
				$transaction->setStatus(TransactionStatus::Saved);
			}

			$booking->setBookingStatus(BookingStatus::Payed);
			$booking->setTransaction($transaction);
			$this->database->setBooking($booking);

			try {
				$course = $this->registry->getInstance(CourseController::class)->getCourse($booking->getBookingForm()->getCourseId());
				$this->registry->getInstance(BookingEmailService::class)->sendEmails($booking, $course);
				return;
			} catch ( InjectionImpossibleException|InvalidResponseException|CourseNotFoundException ) {
				return;
			}
		}

		if ($transaction->getStatus() === TransactionStatus::Failed){
			if ($this->paymentSettings->isCancelBookingIfNoPayment()){
				$this->api->deleteBookingAfterNoPayment($booking->getBookingId(), $transaction->getId());
			}
			$booking->setTransaction($transaction);
			$booking->setBookingStatus(BookingStatus::Failed);
			$this->database->setBooking($booking);
		}
	}
}