<?php

namespace Planaday\Database\InMemoryDatabase;

use Planaday\Entities\Booking\BookingDatabase;
use Planaday\Entities\Booking\DTO\Booking;
use Planaday\Entities\Booking\DTO\BookingForm;
use Planaday\Entities\Booking\DTO\BookingStudent;
use Planaday\Entities\Booking\DTO\Transaction;
use Planaday\Entities\Booking\Enum\BookingStatus;

class InMemoryBookingDB implements BookingDatabase {
	/** @var Booking[] */
	public array $bookings = [];
	public array $passwordBookings = [];

	public function getBooking( string $bookingId ): ?Booking {
		return $this->bookings[$bookingId] ?? null;
	}

	public function setBooking( Booking $booking ): string {
		$id = $booking->getDatabaseId() ?? uniqid();
		$booking->setDatabaseId($id);
		$this->bookings[$id] = $booking;
		return $id;
	}

	public function removeBooking( string $bookingId ): void {
		unset($this->bookings[$bookingId]);
	}

	public function getCountAll(): int {
		return count($this->bookings);
	}

	public function generatePasswordBooking( string $bookingId ): string {
		$this->passwordBookings[$bookingId] = uniqid();
		return $this->passwordBookings[$bookingId];
	}

	public function checkPasswordBooking( string $bookingId, string $password ): bool {
		return $this->passwordBookings[$bookingId] === $password;
	}

	public function removePasswordBooking( string $bookingId ): void {
		unset($this->passwordBookings[$bookingId]);
	}

	public function getTransaction( string $transactionId ): ?Transaction {
		return $this->getBookingByTransaction($transactionId)?->getTransaction();
	}

	public function getBookingByTransaction( string $transactionId ): ?Booking {
		foreach ($this->bookings as $booking){
			$transaction = $booking->getTransaction();
			if($transaction !== null && $transaction->getId() === $transactionId){
				return $booking;
			}
		}
		return null;
	}

	public function removeOldBookings( string $beforeDate ): void {
	}

	public function getAlreadyCompletedBooking( BookingForm $bookingForm ): ?Booking {
		$foundMatch = false;
		foreach ($this->bookings as $booking){
			if($booking->getBookingForm()->getCourseId() === $bookingForm->getCourseId() && $booking->getBookingForm()->getNonce() === $bookingForm->getNonce()){
				$foundMatch = true;
				break;
			}
		}

		if(!$foundMatch) return null;

		if ($booking->getBookingStatus() !== BookingStatus::Successful && $booking->getBookingStatus() !== BookingStatus::Payed)
			return null;

		$databaseForm = $booking->getBookingForm();

		if (count($databaseForm->getStudents()) !== count($bookingForm->getStudents())) return null;
		if (count($databaseForm->getMaterials()) !== count($bookingForm->getMaterials())) return null;
		if (count($databaseForm->getDayParts()) !== count($bookingForm->getDayParts())) return null;

		/** @var BookingStudent $student */
		$studentNames = array_map(fn($student) => $student->getFirstName(), [...$databaseForm->getStudents()]);
		$studentLastNames = array_map(fn($student) => $student->getLastName(), [...$databaseForm->getStudents()]);
		$studentEmails = array_map(fn($student) => $student->getEmail(), [...$databaseForm->getStudents()]);

		foreach ($bookingForm->getStudents() as $student) {
			if (!in_array($student->getFirstName(), $studentNames)) return null;
			if (!in_array($student->getLastName(), $studentLastNames)) return null;
			if (!in_array($student->getEmail(), $studentEmails)) return null;
		}

		$materials = [...$databaseForm->getMaterials()];
		foreach ($bookingForm->getMaterials() as $material) {
			if (!in_array($material, $materials)) return null;
		}

		$dayParts = [...$databaseForm->getDayParts()];
		foreach ($bookingForm->getDayParts() as $dayPart) {
			if (!in_array($dayPart, $dayParts)) return null;
		}

		return $booking;
	}
}