<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\Service\DateUnit;

use BookiFlex\Core\Exception\InvalidArgumentException;
use BookiFlex\Core\Model\AccommodationType\Accommodation\AccommodationType;
use BookiFlex\Core\Model\DateUnit\RestrictionRulesConfigurator;
use BookiFlex\Core\Model\RatePlan\RatePlan;
use BookiFlex\Core\Service\DateUnit\DTO\CalendarData;
use BookiFlex\Core\Service\EntityValidator;
use BookiFlex\Core\ValueObject\AccommodationSelection;
use BookiFlex\Core\ValueObject\StayPeriod;

defined( 'ABSPATH' ) || exit;

class GetCalendar
{
    public function __construct(
        private readonly EntityValidator $entityValidator,
        private readonly DateUnitFinder $dateUnitsFinder,
        private readonly GetMinMaxDates $dates
    ) {
    }

    /**
     * Get calendar data for the specified period and rate plan
     *
     * @throws InvalidArgumentException
     */
    public function getCalendar(\DateTimeImmutable $dateFrom, \DateTimeImmutable $dateTo, int $ratePlanId): CalendarData
    {
        $ratePlan = $this->entityValidator->getRatePlan($ratePlanId);
        $accommodationTypes = $ratePlan->getAccommodationTypes();

        $accommodationTypesData = [];
        $dateUnitsGrouped = [];

        foreach ($accommodationTypes as $accommodationType) {
            // Find date units for this accommodation type
            $dateUnits = $this->dateUnitsFinder->find(
                new StayPeriod($dateFrom, $dateTo),
                new AccommodationSelection($accommodationType->getId(), $ratePlan->getId()),
                new RestrictionRulesConfigurator(
                    ignoreStopSaleRestriction: true,
                    ignoreCTARestriction: true,
                    ignoreCTDRestriction: true,
                    ignoreMinLosRestriction: true,
                    ignoreMaxLosRestriction: true,
                    ignoreMinLosArrivalRestriction: true,
                    ignoreMaxLosArrivalRestriction: true,
                    ignoreMinAdvBookingRestriction: true,
                    ignoreMaxAdvBookingRestriction: true
                )
            );

            $accommodationTypeId = $accommodationType->getId();

            // Store accommodation type data with sync status
            $accommodationTypesData[] = [
                'accommodationType' => $accommodationType,
                'isSync' => $this->checkSync($ratePlan, $accommodationType),
            ];

            // Group date units by accommodation type ID
            $dateUnitsGrouped[$accommodationTypeId] = $dateUnits->getDateUnits();
        }

        return new CalendarData(
            ratePlan: $ratePlan,
            accommodationTypesData: $accommodationTypesData,
            dateUnitsGrouped: $dateUnitsGrouped
        );
    }

    /**
     * Check if child rate plan is synchronized with parent
     */
    private function checkSync(RatePlan $ratePlan, AccommodationType $accommodationType): bool
    {
        if (!$ratePlan->isChildRatePlan()) {
            return true;
        }

        $parentMinMaxDates = $this->dates->getMinMaxDates($ratePlan->getParent()->getId(), $accommodationType->getId());
        $childMinMaxDates  = $this->dates->getMinMaxDates($ratePlan->getId(), $accommodationType->getId());

        if (
            ($parentMinMaxDates['max'] !== null && $childMinMaxDates['max'] === null)
            || $childMinMaxDates['max'] < $parentMinMaxDates['max']
        ) {
            return false;
        }

        return true;
    }
}
