<?php
namespace EasyChat\Library\Ai;

use EasyChat\Library\AppClock;
use EasyChat\Library\PresenceService;
use EasyChat\Model\Setting;








class AiResponseTimingPolicy {
    public const MODE_STRICT_DELAY = 'strict_delay';
    public const MODE_OPERATOR_BACKUP = 'operator_backup';
    public const SETTING_MODE = 'chat_ai_response_timing_mode';
    public const SETTING_OFFLINE_DELAY_SECONDS = 'chat_ai_offline_delay_seconds';
    public const DEFAULT_DELAY_MINUTES = 2;
    public const DEFAULT_OFFLINE_DELAY_SECONDS = 30;
    public const MAX_DELAY_MINUTES = 60;
    public const MAX_OFFLINE_DELAY_SECONDS = 600;
    public const OPERATOR_BACKUP_RECHECK_SECONDS = 30;

    private $setting;
    private $presence;
    private $clock;

    public function __construct($registry) {
        $this->setting = new Setting($registry);
        $this->presence = new PresenceService($registry);
        $this->clock = new AppClock($registry);
    }

    public static function normalizeMode($mode): string {
        $mode = trim((string)$mode);
        return in_array($mode, [self::MODE_STRICT_DELAY, self::MODE_OPERATOR_BACKUP], true)
            ? $mode
            : self::MODE_STRICT_DELAY;
    }

    public static function normalizeDelayMinutes($value): int {
        $minutes = (int)$value;
        if ($minutes < 0) {
            return 0;
        }
        if ($minutes > self::MAX_DELAY_MINUTES) {
            return self::MAX_DELAY_MINUTES;
        }
        return $minutes;
    }

    public static function normalizeOfflineDelaySeconds($value): int {
        $seconds = (int)$value;
        if ($seconds < 0) {
            return 0;
        }
        if ($seconds > self::MAX_OFFLINE_DELAY_SECONDS) {
            return self::MAX_OFFLINE_DELAY_SECONDS;
        }
        return $seconds;
    }

    public function mode(): string {
        return self::normalizeMode($this->setting->get(self::SETTING_MODE, self::MODE_STRICT_DELAY));
    }

    public function onlineDelaySeconds(): int {
        return self::normalizeDelayMinutes($this->setting->get('chat_ai_delay', self::DEFAULT_DELAY_MINUTES)) * 60;
    }

    public function offlineDelaySeconds(): int {
        return self::normalizeOfflineDelaySeconds(
            $this->setting->get(self::SETTING_OFFLINE_DELAY_SECONDS, self::DEFAULT_OFFLINE_DELAY_SECONDS)
        );
    }

    public function hasOnlineManagers(): bool {
        return $this->presence->hasOnlineManagers();
    }

    public function initialQueueDelaySeconds(): int {
        if ($this->mode() !== self::MODE_OPERATOR_BACKUP) {
            return $this->onlineDelaySeconds();
        }

        if (!$this->hasOnlineManagers()) {
            return $this->offlineDelaySeconds();
        }

        $online_delay = $this->onlineDelaySeconds();
        if ($online_delay <= 0) {
            return 0;
        }

         
         
         
        return min(self::OPERATOR_BACKUP_RECHECK_SECONDS, $online_delay);
    }

    public function evaluateForMessageDate(string $date_added): array {
        $mode = $this->mode();
        $online_delay_seconds = $this->onlineDelaySeconds();
        $operator_online = false;
        $required_seconds = $online_delay_seconds;

        if ($mode === self::MODE_OPERATOR_BACKUP) {
            $operator_online = $this->hasOnlineManagers();
            $required_seconds = $operator_online
                ? $online_delay_seconds
                : $this->offlineDelaySeconds();
        }

        $elapsed_seconds = $this->clock->secondsSinceSql($date_added);
        $remaining_seconds = max(0, $required_seconds - $elapsed_seconds);

        return [
            'ready' => $remaining_seconds <= 0,
            'mode' => $mode,
            'operator_online' => $operator_online,
            'required_seconds' => $required_seconds,
            'elapsed_seconds' => $elapsed_seconds,
            'remaining_seconds' => $remaining_seconds,
            'retry_after' => $this->retryAfterSeconds($mode, $operator_online, $remaining_seconds),
            'now_sql' => $this->clock->nowSql(),
        ];
    }

    private function retryAfterSeconds(string $mode, bool $operator_online, int $remaining_seconds): int {
        if ($remaining_seconds <= 0) {
            return 0;
        }

        if ($mode === self::MODE_OPERATOR_BACKUP && $operator_online) {
            return max(1, min(self::OPERATOR_BACKUP_RECHECK_SECONDS, $remaining_seconds));
        }

        return max(1, min(60, $remaining_seconds));
    }
}
