<?php

namespace Planaday\Api\Mock;

use ArrayAccess;
use Countable;
use DateInterval;
use DateTime;
use DateTimeZone;
use Planaday\Entities\DayPart\DayPartApi;
use Planaday\Entities\DayPart\DTO\DayPart;
use Planaday\Entities\DayPart\DTO\DayPartUsersData;
use Planaday\Entities\DayPart\Exception\DayPartNotFoundException;
use Planaday\Utility\DataGrouping\Collection;
use Planaday\Utility\Debug\Log\Logging;
use Traversable;

class MockDayPartApi implements DayPartApi {
	use Logging;
	protected DayPartApi|null $dayPartApiMock = null;

	/** @var Collection<DayPart> */
	protected Collection $dayParts;

	public function __construct() {
		$this->logInfo("MockDayPartApi constructed");
		$this->dayParts = new Collection();
		$dayParts = range(1, 30);
		foreach ($dayParts as $dayPartId) {
			$this->dayParts->append($this->getTestDayPart($dayPartId));
		}
		$this->logInfo("Day parts added, count: " . count($this->dayParts));
	}

	/**
	 * @inheritDoc
	 */
	public function getDayPartsCourse( int $courseId, int $offset = 0, int $limit = 100 ): ArrayAccess&Traversable&Countable {
		if ( $this->dayPartApiMock !== null ) return $this->dayPartApiMock->getDayPartsCourse( $courseId, $offset, $limit );

		$this->logInfo("MockDayPartApi getting day parts for course $courseId");
		$items = [];
		foreach ( $this->dayParts as $dayPart ) {
			if ( $dayPart->getCourseId() === $courseId ) {
				$items[] = $dayPart;
			}
		}

		return Collection::fromArray($items);
	}

	/**
	 * @inheritDoc
	 */
	public function getDayPart( int $dayPartId ): DayPart {
		if ( $this->dayPartApiMock !== null ) return $this->dayPartApiMock->getDayPart( $dayPartId );

		$this->logInfo("MockDayPartApi getting day part $dayPartId");
		if (isset($this->dayParts[$dayPartId - 1])) {
			return $this->dayParts[$dayPartId - 1];
		}

		throw new DayPartNotFoundException("DayPart with ID $dayPartId not found");
	}

	private function getTestDayPart( $dayPartId ): DayPart {
		$courseId = (int) floor($dayPartId / 3) + 1;
		$locationId = ($dayPartId % 3) + 1;

		/** @noinspection PhpUnhandledExceptionInspection always safe with these constraints */
		$start = (new DateTime())
			->setTimezone(new DateTimeZone('Europe/Amsterdam'))
			->add( new DateInterval('P' . $courseId . 'DT' . $locationId . '0M'));

		/** @noinspection PhpUnhandledExceptionInspection always safe with these constraints */
		$end = (new DateTime())
			->setTimezone(new DateTimeZone('Europe/Amsterdam'))
			->add( new DateInterval('P' . $courseId . 'DT' . $locationId . 'H'));


		return (new DayPart( $dayPartId, $courseId ))
			->setName("Test dagdeel $dayPartId")
			->setDescription("Dit is een test dagdeel (id: $dayPartId), deze wordt weergeven omdat er nog geen koppeling is gemaakt met planaday.")
			->setLocationIds( ['l' . $locationId] )
			->setUsersData(
				(new DayPartUsersData())
					->setAvailable(10)
					->setMax(10)
			)->setLabels(["test label"])
			->setVisible(true)
			->setStartTime($start)
			->setEndTime($end);
	}

	public function getDayParts( Countable&Traversable&ArrayAccess $dayPartIds ):ArrayAccess&Traversable&Countable {
		if ( $this->dayPartApiMock !== null ) return $this->dayPartApiMock->getDayParts( $dayPartIds );

		$response = [];

		$this->logInfo("MockDayPartApi getting day parts " . implode(", ", [...$dayPartIds]));
		foreach ($dayPartIds as $dayPartId) {
			$response[] = $this->getDayPart($dayPartId);
		}
		$this->logInfo("MockDayPartApi returning " . count($response) . " day parts");

		return Collection::fromArray($response);
	}
}