<?php

declare(strict_types=1);

namespace app\common\library\token\driver;

use support\think\Db;
use app\common\library\token\Driver;

/**
 * Token Mysql 驱动
 * @see Driver
 */
class Mysql extends Driver
{
    protected array $options = [];

    public function __construct(array $options = [])
    {
        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }

        if (!empty($this->options['name'])) {
            $this->handler = Db::connect($this->options['name'])->name($this->options['table']);
        } else {
            $this->handler = Db::name($this->options['table']);
        }
    }

    public function set(string $token, string $type, int $userId, ?int $expire = null): bool
    {
        if ($expire === null) {
            $expire = $this->options['expire'] ?? 2592000;
        }
        $expireTime = $expire !== 0 ? time() + $expire : 0;
        $encryptedToken = $this->getEncryptedToken($token);
        $this->handler->insert([
            'token'       => $encryptedToken,
            'type'        => $type,
            'user_id'     => $userId,
            'create_time' => time(),
            'expire_time' => $expireTime,
        ]);

        // 每隔 48 小时清理一次过期 Token
        $time = time();
        $lastCacheCleanupTime = $this->getLastCacheCleanupTime();
        if (!$lastCacheCleanupTime || $lastCacheCleanupTime < $time - 172800) {
            $this->setLastCacheCleanupTime($time);
            $this->handler->where('expire_time', '<', time())->where('expire_time', '>', 0)->delete();
        }
        return true;
    }

    public function get(string $token): array
    {
        $data = $this->handler->where('token', $this->getEncryptedToken($token))->find();
        if (!$data) {
            return [];
        }

        $data['token'] = $token;
        $data['expires_in'] = $this->getExpiredIn($data['expire_time'] ?? 0);
        return $data;
    }

    public function check(string $token, string $type, int $userId): bool
    {
        $data = $this->get($token);
        if (!$data || ($data['expire_time'] && $data['expire_time'] <= time())) {
            return false;
        }
        return $data['type'] == $type && $data['user_id'] == $userId;
    }

    public function delete(string $token): bool
    {
        $this->handler->where('token', $this->getEncryptedToken($token))->delete();
        return true;
    }

    public function clear(string $type, int $userId): bool
    {
        $this->handler->where('type', $type)->where('user_id', $userId)->delete();
        return true;
    }

    /**
     * 使用文件存储 last_cache_cleanup_time（兼容无 cache 插件环境）
     */
    private function getLastCacheCleanupTime(): ?int
    {
        $path = $this->getCleanupTimePath();
        if (!is_file($path)) {
            return null;
        }
        $v = file_get_contents($path);
        return $v !== false && $v !== '' ? (int) $v : null;
    }

    private function setLastCacheCleanupTime(int $time): void
    {
        $path = $this->getCleanupTimePath();
        $dir = dirname($path);
        if (!is_dir($dir)) {
            @mkdir($dir, 0755, true);
        }
        @file_put_contents($path, (string) $time);
    }

    private function getCleanupTimePath(): string
    {
        $base = defined('RUNTIME_PATH') ? RUNTIME_PATH : (base_path() . DIRECTORY_SEPARATOR . 'runtime');
        return $base . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'token_last_cleanup.txt';
    }
}
