<?php

declare(strict_types=1);

namespace Autogedal\FeedMonitor\Model;

use Magento\Framework\App\ResourceConnection;

/**
 * Alert state per monitored key (autogedal_feed_monitor_state).
 */
class StateRepository
{
    public const ALLOWANCE_HOURS = 24;

    private const TABLE = 'autogedal_feed_monitor_state';

    public function __construct(
        private readonly ResourceConnection $resource,
        private readonly Clock $clock
    ) {
    }

    public function get(string $key): ?array
    {
        $connection = $this->resource->getConnection();
        $row = $connection->fetchRow($connection->select()->from($this->table())->where('monitor_key = ?', $key));

        return $row ?: null;
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public function getOpenAlerts(): array
    {
        $connection = $this->resource->getConnection();

        return $connection->fetchAll($connection->select()->from($this->table())->where('alert_open = 1'));
    }

    /**
     * @param array<string, mixed> $data
     */
    public function save(string $key, array $data): void
    {
        $data['monitor_key'] = $key;
        $data['updated_at'] = $this->clock->format();
        $this->resource->getConnection()->insertOnDuplicate($this->table(), $data, array_keys($data));
    }

    /**
     * Records when a key was first watched (the reference for "not running" when it never ran), returns it.
     */
    public function watchedSince(string $key): int
    {
        $state = $this->get($key);
        if ($state && $state['watched_since']) {
            return (int)strtotime($state['watched_since'] . ' UTC');
        }
        $this->save($key, ['watched_since' => $this->clock->format()]);

        return $this->clock->now();
    }

    public function allowIncomplete(string $key, int $hours = self::ALLOWANCE_HOURS): void
    {
        $this->save($key, ['allow_incomplete_until' => $this->clock->format($this->clock->now() + $hours * 3600)]);
    }

    /**
     * True once after allowIncomplete(), while it has not expired.
     */
    public function consumeIncompleteAllowance(string $key): bool
    {
        $affected = $this->resource->getConnection()->update(
            $this->table(),
            ['allow_incomplete_until' => null, 'updated_at' => $this->clock->format()],
            ['monitor_key = ?' => $key, 'allow_incomplete_until >= ?' => $this->clock->format()]
        );

        return $affected > 0;
    }

    private function table(): string
    {
        return $this->resource->getTableName(self::TABLE);
    }
}
