<?php

/**
 * 文件功能：节日福利年度调度校验规则
 *
 * 负责校验 yearly 模式下的月/日/时间、多天与多轮次组合是否合法。
 */

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Translation\PotentiallyTranslatedString;

/**
 * 类功能：校验节日福利年度调度配置的组合合法性。
 */
class HolidayEventScheduleRule implements DataAwareRule, ValidationRule
{
    /**
     * 当前请求的全部字段。
     *
     * @var array<string, mixed>
     */
    protected array $data = [];

    /**
     * 注入待校验的完整数据集。
     *
     * @param  array<string, mixed>  $data
     */
    public function setData(array $data): static
    {
        $this->data = $data;

        return $this;
    }

    /**
     * 运行年度调度规则校验。
     *
     * @param  Closure(string, ?string=): PotentiallyTranslatedString  $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $repeatType = (string) ($this->data['repeat_type'] ?? $value ?? '');

        if ($repeatType !== 'yearly') {
            return;
        }

        $month = (int) ($this->data['schedule_month'] ?? 0);
        $day = (int) ($this->data['schedule_day'] ?? 0);
        $time = (string) ($this->data['schedule_time'] ?? '');
        $durationDays = (int) ($this->data['duration_days'] ?? 0);
        $dailyOccurrences = (int) ($this->data['daily_occurrences'] ?? 0);
        $intervalMinutes = $this->data['occurrence_interval_minutes'];

        if ($month < 1 || $month > 12) {
            $fail('年度节日模式必须设置有效的触发月份。');
        }

        if ($day < 1 || $day > 31) {
            $fail('年度节日模式必须设置有效的触发日期。');
        }

        if ($month > 0 && $day > 0 && ! checkdate($month, $day, 2024)) {
            $fail('所选月份和日期不是有效的公历节日日期。');
        }

        if (! preg_match('/^\d{2}:\d{2}$/', $time)) {
            $fail('年度节日模式必须设置首轮开始时间。');

            return;
        }

        if ($durationDays < 1 || $durationDays > 31) {
            $fail('连续发放天数必须在 1 到 31 天之间。');
        }

        if ($dailyOccurrences < 1 || $dailyOccurrences > 24) {
            $fail('每天发送次数必须在 1 到 24 次之间。');
        }

        if ($dailyOccurrences > 1 && ((int) $intervalMinutes) < 1) {
            $fail('同一天多轮发送时，必须设置大于 0 的间隔分钟数。');
        }

        [$hour, $minute] = array_map('intval', explode(':', $time));
        $startMinutes = $hour * 60 + $minute;
        $lastOffsetMinutes = max(0, ($dailyOccurrences - 1) * (int) ($intervalMinutes ?? 0));

        if ($startMinutes + $lastOffsetMinutes >= 1440) {
            $fail('同一天多轮发送的最后一轮不能跨到次日，请缩短间隔或减少次数。');
        }
    }
}
