<?php

declare(strict_types=1);

namespace Kylin\Export\Services;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;

/**
 * 下载链接 Token 服务
 *
 * 依据《数据安全法》第二十一条：
 * 数据下载需验证身份，防止未授权下载。
 *
 * 使用方式：
 *   // 生成下载 Token
 *   $token = DownloadToken::generate($exportId, $userId);
 *   // 验证下载 Token
 *   DownloadToken::verify($token, $exportId);
 *
 * 路由示例：
 *   Route::get('/export/{id}/download/{token}', [ExportController::class, 'download']);
 */
final class DownloadToken
{
    /**
     * Token 有效期（分钟）
     */
    private const TTL_MINUTES = 30;

    /**
     * Token 长度
     */
    private const TOKEN_LENGTH = 64;

    /**
     * 生成下载 Token
     *
     * @param int $exportId 导出记录 ID
     * @param int $userId 用户 ID
     * @return string 下载 Token
     */
    public static function generate(int $exportId, int $userId): string
    {
        $token = Str::random(self::TOKEN_LENGTH);
        $key = self::cacheKey($exportId);

        Cache::put($key, [
            'token' => $token,
            'user_id' => $userId,
            'export_id' => $exportId,
            'created_at' => now()->toDateTimeString(),
        ], now()->addMinutes(self::TTL_MINUTES));

        return $token;
    }

    /**
     * 验证下载 Token
     *
     * @param string $token 下载 Token
     * @param int $exportId 导出记录 ID
     * @return bool 验证结果
     */
    public static function verify(string $token, int $exportId): bool
    {
        $key = self::cacheKey($exportId);
        $data = Cache::get($key);

        if (! $data) {
            return false;
        }

        if (! hash_equals($data['token'], $token)) {
            return false;
        }

        if ($data['export_id'] !== $exportId) {
            return false;
        }

        return true;
    }

    /**
     * 获取 Token 关联的导出 ID
     */
    public static function getExportId(string $token): ?int
    {
        $key = "export:token:{$token}";
        return Cache::get($key);
    }

    /**
     * 获取 Token 信息
     *
     * @return array|null
     */
    public static function getTokenInfo(int $exportId): ?array
    {
        $key = self::cacheKey($exportId);
        return Cache::get($key);
    }

    /**
     * 撤销 Token
     */
    public static function revoke(int $exportId): void
    {
        $key = self::cacheKey($exportId);
        Cache::forget($key);
    }

    /**
     * 获取 Token 有效期
     */
    public static function ttl(): int
    {
        return self::TTL_MINUTES;
    }

    /**
     * 生成缓存键
     */
    private static function cacheKey(int $exportId): string
    {
        return "export:download_token:{$exportId}";
    }
}