<?php

namespace Velis\MaintenanceAlert;

use DateTimeImmutable;
use DateTimeZone;
use Exception;
use Velis\Timezone\DateTimeZoneProvider;

/**
 * @author Szymon Janaczek <szymon.janaczek@velistech.com>
 */
final class MaintenanceAlertGenerator implements MaintenanceAlertGeneratorInterface
{
    private DateTimeImmutable $maintenanceDateStop;
    private DateTimeZone $userTimeZone;
    private DateTimeZone $applicationDefaultTimeZone;
    private bool $multipleTimeZoneSupport;

    /**
     * @throws Exception
     */
    public function __construct(
        private readonly MaintenanceAlertFormatterInterface $alertFormatter,
        ?string $userTimeZone = null,
        ?string $applicationDefaultTimeZone = null,
    ) {
        $timeZoneProvider = new DateTimeZoneProvider();

        if (is_string($userTimeZone)) {
            $this->userTimeZone = $timeZoneProvider->get($userTimeZone);
        }

        if (is_string($applicationDefaultTimeZone)) {
            $this->applicationDefaultTimeZone = $timeZoneProvider->get($applicationDefaultTimeZone);
        }
    }

    /**
     * @throws Exception
     */
    public function getAlert(
        string $maintenanceDateStart,
        string $maintenanceDateStop,
        string $maintenanceTimeZone,
        bool $multipleTimeZoneSupport,
    ): ?string {
        $this->multipleTimeZoneSupport = $multipleTimeZoneSupport;

        if ($this->multipleTimeZoneSupport && !isset($this->userTimeZone)) {
            throw new Exception('User timezone must be provided when multiple timezone support is enabled.');
        }

        if (!$this->multipleTimeZoneSupport && !isset($this->applicationDefaultTimeZone)) {
            throw new Exception('Application timezone must be provided when multiple timezone support is disabled.');
        }

        $maintenanceTimeZone1 = new DateTimeZone($maintenanceTimeZone);
        $maintenanceDateStart1 = new DateTimeImmutable($maintenanceDateStart, $maintenanceTimeZone1);
        $this->maintenanceDateStop = new DateTimeImmutable($maintenanceDateStop, $maintenanceTimeZone1);

        if ($this->isMaintenanceOver()) {
            return null;
        }

        $startDate = $this->getAdjustedDate($maintenanceDateStart1);
        $stopDate = $this->getAdjustedDate($this->maintenanceDateStop);

        return $this->alertFormatter->format($startDate, $stopDate);
    }

    /**
     * @throws Exception
     */
    private function isMaintenanceOver(): bool
    {
        $currentDate = new DateTimeImmutable('now', $this->getOutputTimeZone());

        return $currentDate >= $this->getAdjustedDate($this->maintenanceDateStop);
    }

    private function getAdjustedDate(DateTimeImmutable $date): DateTimeImmutable
    {
        return $date->setTimezone($this->getOutputTimeZone());
    }

    private function getOutputTimeZone(): DateTimeZone
    {
        return $this->multipleTimeZoneSupport ? $this->userTimeZone : $this->applicationDefaultTimeZone;
    }
}
