<?php

namespace Planaday\Entities\Booking;

use Planaday\Api\ApiException\InvalidResponseException;
use Planaday\Entities\Booking\DTO\Booking;
use Planaday\Entities\Booking\DTO\BookingForm;
use Planaday\Entities\Course\DTO\Course;
use Planaday\Entities\Voucher\Exception\BookingNotFoundException;
use Planaday\Entities\Voucher\Exception\VoucherInvalidException;
use Planaday\Entities\Voucher\Exception\VoucherNotFoundException;
use Planaday\Entities\Voucher\VoucherApi;
use Planaday\Entities\Voucher\VoucherType;
use Planaday\Utility\DataGrouping\ArrayFunctions;
use Planaday\Utility\Debug\Log\Logging;

class BookingPriceService {
	use Logging;

	public function __construct(
		protected VoucherApi $voucherApi
	) {}

	public function calculatePriceBooking(Booking $booking, Course $course): float {
		$form = $booking->getBookingForm();

		$cost = $this->calculateCoursePrice($form, $course);

		if ($cost > 0)
			$cost = max(0, $this->applyVoucher($booking, $course, $cost));

		$cost += $this->calculateMaterialsPrice($form, $course);

		return $cost;
	}

	protected function calculateMaterialsPrice(BookingForm $form, Course $course): float {
		$totalCost = 0;
		$perStudentCost = 0;

		foreach ($course->getMaterials() as $courseMaterial) {
			if (ArrayFunctions::in_array($courseMaterial->getId(), $form->getMaterials())) {
				if ($courseMaterial->isInvoicedPerCompany()){
					$totalCost += $courseMaterial->getCostsData()->getPriceWithTax() * ($courseMaterial->getAmount());
				} elseif ( $courseMaterial->isInvoicedPerStudent() ) {
					$perStudentCost += $courseMaterial->getCostsData()->getPriceWithTax();
				}
			}
		}

		return $totalCost + $perStudentCost * count($form->getStudents());
	}

	protected function calculateCoursePrice(BookingForm $form, Course $course): float {
		$perStudentCost = 0;

		if ($course->isPriceFromDayParts()){
			foreach ( $course->getDayParts() as $dayPart) {
				if (!in_array($dayPart->getId(), [...$form->getDayParts()])) continue;
				$perStudentCost += $dayPart->getCostsData()->getPriceWithTax();
			}
		} else {
			$perStudentCost = $course->getCostsData()->getPriceWithTax();
		}

		return $perStudentCost * count($form->getStudents());
	}

	protected function applyVoucher(Booking $booking, Course $course, float $courseCost): float {
		$form = $booking->getBookingForm();

		if( $form->getVoucherCode() === null ) return $courseCost;

		try {
			$voucher = $this->voucherApi->getVoucher(trim($form->getVoucherCode()));
		} catch (VoucherNotFoundException|InvalidResponseException|VoucherInvalidException){
			return $courseCost;
		}

		if ($voucher->isForCourseTemplate() && $course->getTemplateId() != $voucher->getCourseTemplate()) return $courseCost;

		if ($bookingId = $booking->getBookingId()){
			try{
				$this->voucherApi->useVoucher($voucher, $bookingId);
			} catch ( InvalidResponseException|BookingNotFoundException|VoucherNotFoundException $e ) {
				$this->logError("Use voucher failed: " . $e->getMessage(), $e);
			}
		}

		return match ( $voucher->getType() ) {
			VoucherType::Amount => $courseCost - $voucher->getAmount(),
			VoucherType::Percentage => $courseCost * ( 1 - ( $voucher->getAmount() / 100 ) ),
			default => $courseCost,
		};
	}
}