<?php

declare(strict_types=1);

/**
 * Created by Aurélien RICHAUD (01/08/2017 16:51).
 */
class CliniqueHolidays extends ObjectModel
{
    public const TABLE = 'myvetshop_clinique_holidays';

    /**
     * @var int
     */
    public $id_myvetshop_clinique;

    /**
     * @var string
     */
    public $date_alerte;

    /**
     * @var string
     */
    public $date_debut;

    /**
     * @var string
     */
    public $date_fin;

    /**
     * @var string
     */
    public $message_alerte;

    /**
     * @var string
     */
    public $message;

    /**
     * @see ObjectModel::$definition
     *
     * @var array<mixed>
     */
    public static $definition = [
        'table' => self::TABLE,
        'primary' => 'id_myvetshop_clinique_holidays',
        'multilang' => false,
        'multilang_shop' => false,
        'fields' => [
            // Clés étrangères
            'id_myvetshop_clinique' => ['type' => self::TYPE_INT, 'required' => true],
            'date_alerte' => ['type' => self::TYPE_DATE, 'required' => false],
            'date_debut' => ['type' => self::TYPE_DATE, 'required' => true, 'validate' => 'isDate'],
            'date_fin' => ['type' => self::TYPE_DATE, 'required' => true, 'validate' => 'isDate'],
            'message_alerte' => ['type' => self::TYPE_STRING, 'required' => false, 'size' => 1000],
            'message' => ['type' => self::TYPE_STRING, 'required' => true, 'size' => 1000],
        ],
    ];

    public function getMessage(): ?string
    {
        if ($this->hasAlertActive()) {
            return $this->message_alerte;
        }

        if ($this->isActive()) {
            return $this->message;
        }

        return null;
    }

    public function hasAlertActive(): bool
    {
        $alert = DateTime::createFromFormat('Y-m-d', $this->date_alerte) ?: null;
        $start = $this->getStartDate();

        return null !== $start
            && null !== $alert
            && $alert->getTimestamp() > 0
            && $alert->getTimestamp() < $start->getTimestamp();
    }

    public function isActive(): bool
    {
        $now = new DateTime();
        $start = $this->getStartDate();
        $end = $this->getEndDate();

        return null !== $start
            && null !== $end
            && ($start->getTimestamp() <= $now->getTimestamp())
            && ($now->getTimestamp() <= $end->getTimestamp());
    }

    public function getStartDate(): ?DateTime
    {
        return $this->getDate($this->date_debut);
    }

    public function getEndDate(): ?DateTime
    {
        return $this->getDate($this->date_fin);
    }

    public function getAlertDate(): ?DateTime
    {
        return $this->getDate($this->date_alerte);
    }

    protected function getDate(string $date): ?DateTime
    {
        $dateTime = DateTime::createFromFormat('Y-m-d', $date);

        return $dateTime && $dateTime->getTimestamp() > 0 ? $dateTime : null;
    }

    public static function getCliniqueMessage(int $cliniqueId): ?string
    {
        $holidays = self::getHolidays($cliniqueId);

        if (empty($holidays)) {
            $holidays = self::getHolidaysSoon($cliniqueId);
        }

        $holiday = array_shift($holidays);

        return $holiday ? $holiday->getMessage() : null;
    }

    /**
     * Congé en cours pour la clinique (entre date d'alerte et fin de congé !).
     */
    public static function getCurrentHolliday(int $cliniqueId): ?self
    {
        return self::getByCliniqueId($cliniqueId)[0] ?? null;
    }

    /**
     * @return CliniqueHolidays[]
     */
    public static function getHolidaysSoon(int $cliniqueId): array
    {
        return array_filter(
            self::getByCliniqueId($cliniqueId),
            fn (CliniqueHolidays $cliniqueHolidays) => $cliniqueHolidays->hasAlertActive()
        );
    }

    /**
     * @return CliniqueHolidays[]
     */
    public static function getHolidays(int $cliniqueId): array
    {
        return array_filter(
            self::getByCliniqueId($cliniqueId),
            fn (CliniqueHolidays $cliniqueHolidays) => $cliniqueHolidays->isActive()
        );
    }

    public static function hasCliniqueOnHolidaysSoon(int $cliniqueId): bool
    {
        return !empty(self::getHolidaysSoon($cliniqueId));
    }

    public static function hasCliniqueOnHolidays(int $cliniqueId): bool
    {
        return !empty(self::getHolidays($cliniqueId));
    }

    /**
     * Liste les congés en cours pour une clinique.
     *
     * @return CliniqueHolidays[]
     *
     * @throws PrestaShopDatabaseException
     */
    public static function getByCliniqueId(int $cliniqueId): array
    {
        $query = (new DbQuery())
            ->select(\strval(self::$definition['primary']))
            ->from(self::TABLE)
            ->where('id_myvetshop_clinique=' . $cliniqueId)
            ->where(' CURDATE() BETWEEN date_debut'
                . ' AND date_fin'
                . ' OR ('
                . 'date_alerte NOT LIKE "0000-00-00"'
                . ' AND "' . date('Y-m-d') . '" BETWEEN date_alerte'
                . ' AND date_debut'
                . ')');
        $rawList = Db::getInstance()->executeS($query);
        if (!\is_array($rawList)) {
            $rawList = [];
        }

        $list = \array_column($rawList, self::$definition['primary']);

        return \array_map(fn ($cliniqueHolidaysId) => new self($cliniqueHolidaysId), $list);
    }

    public static function get(int $cliniqueHolidayId): ?self
    {
        $cliniqueHoliday = new self($cliniqueHolidayId);

        return Validate::isLoadedObject($cliniqueHoliday) ? $cliniqueHoliday : null;
    }

    public static function install(): bool
    {
        $query = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . static::TABLE . '` (
              `id_myvetshop_clinique_holidays`  INT(11) NOT NULL AUTO_INCREMENT,
              `id_myvetshop_clinique` INT(11) NOT NULL,
              `date_alerte` DATE NULL,
              `date_debut` DATE NOT NULL,
              `date_fin` DATE NOT NULL,
              `message_alerte` TEXT NULL,
              `message` TEXT NOT NULL,
               PRIMARY KEY (id_myvetshop_clinique_holidays)
            );';

        return Db::getInstance()->execute($query);
    }
}
