<?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\RatePlan\RatePlan;
use BookiFlex\Core\Provider\LocalTimeZone;
use BookiFlex\Core\Service\EntityValidator;
use BookiFlex\Core\Util\DateTimeUtils;
use DateTimeImmutable;

defined( 'ABSPATH' ) || exit;

/**
 * Sync DateUnits with parent rate plan.
 */
class DateUnitSynchronization
{
    public function __construct(
        private readonly EntityValidator $entityValidator,
        private readonly DateUnitExtender $prolongDateUnitsHandler,
        private readonly GetMinMaxDates $getMinMaxDates,
    ) {
    }

    /**
     * Sync child rate plan DateUnits with parent rate plan
     *
     * @throws InvalidArgumentException
     */
    public function sync(int $ratePlanId, int $accommodationTypeId): void
    {
        $ratePlan = $this->validateAndGetChildRatePlan($ratePlanId);
        $accommodationType = $this->entityValidator->getAccommodationTypeFromRatePlan(
            $ratePlan,
            $accommodationTypeId
        );

        $dateRange = $this->getDateRangeFromParent($ratePlan->getParent(), $accommodationType);

        $this->prolongDateUnitsHandler->handle(
            new DTO\ExtendDateUnits(
                $ratePlan,
                [$accommodationType],
                $dateRange['min'],
                $dateRange['max'],
                $this->getAllWeekDays()
            )
        );
    }

    /**
     * Validate and get child rate plan
     *
     * @throws InvalidArgumentException
     */
    private function validateAndGetChildRatePlan(int $ratePlanId): RatePlan
    {
        $ratePlan = $this->entityValidator->getRatePlan($ratePlanId);

        if (!$ratePlan->isChildRatePlan()) {
            throw new InvalidArgumentException('Rate plan is not child');
        }

        return $ratePlan;
    }

    /**
     * Get date range from parent rate plan
     *
     * @throws InvalidArgumentException
     */
    private function getDateRangeFromParent(
        RatePlan $parentRatePlan,
        AccommodationType $accommodationType
    ): array {
        ['min' => $minDate, 'max' => $maxDate] = $this->getMinMaxDates->getMinMaxDates(
            $parentRatePlan->getId(),
            $accommodationType->getId()
        );

        if ($minDate === null || $maxDate === null) {
            throw new InvalidArgumentException('No parent date units found');
        }

        $today = DateTimeUtils::nowAtLocalTimeZone()->format('Y-m-d');

        if ($today > $maxDate) {
            throw new InvalidArgumentException('Parent rate plan does not exist in the future.');
        }

        // Adjust min date if it's in the past
        if ($today > $minDate) {
            $minDate = $today;
        }

        return [
            'min' => DateTimeImmutable::createFromFormat('Y-m-d', $minDate, LocalTimeZone::get()),
            'max' => DateTimeImmutable::createFromFormat('Y-m-d', $maxDate, LocalTimeZone::get()),
        ];
    }

    /**
     * Get all week days configuration
     */
    private function getAllWeekDays(): array
    {
        return [
            'mon' => true,
            'tue' => true,
            'wed' => true,
            'thu' => true,
            'fri' => true,
            'sat' => true,
            'sun' => true
        ];
    }
}
