<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Tools\Support;

use App\Support\DberpSystemProfileSettings;
use App\Tools\Exceptions\ToolInvalidInputException;
use App\Tools\ToolExecutionContext;
use DateTimeImmutable;
use DateTimeZone;
use Throwable;

/**
 * Tool 业务日历日。只接受 Y-m-d，不解析任意自然语言或带时区的时间戳。
 *
 * 日历日本身不换算存储时区；whereDate 等现有报表过滤仍按库中日期部分比较，
 * 避免静默改写历史 UTC 时间戳的业务含义。默认“今天”使用执行上下文时区。
 */
final class ToolBusinessDate
{
    public const FORMAT = 'Y-m-d';

    public static function resolveTimezone(?string $timezone): string
    {
        $candidate = is_string($timezone) ? trim($timezone) : '';

        if ($candidate !== '' && in_array($candidate, timezone_identifiers_list(), true)) {
            return $candidate;
        }

        return DberpSystemProfileSettings::displayTimezone();
    }

    public static function timezoneFromContext(ToolExecutionContext $context): string
    {
        return self::resolveTimezone($context->timezone);
    }

    public static function today(?string $timezone): string
    {
        $tz = self::resolveTimezone($timezone);

        return now($tz)->toDateString();
    }

    public static function parse(string $value, string $field): string
    {
        $trimmed = trim($value);

        if (! self::isValid($trimmed)) {
            throw ToolInvalidInputException::forField($field, 'Date must use Y-m-d.');
        }

        return $trimmed;
    }

    public static function isValid(string $value): bool
    {
        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) !== 1) {
            return false;
        }

        try {
            $parsed = DateTimeImmutable::createFromFormat('!'.self::FORMAT, $value, new DateTimeZone('UTC'));
        } catch (Throwable) {
            return false;
        }

        return $parsed instanceof DateTimeImmutable && $parsed->format(self::FORMAT) === $value;
    }
}
