import * as fs from 'expo-file-system/legacy';
import { createMMKV, MMKV } from 'react-native-mmkv';

const TTL_KEY = '$__$t_';
const LAST_CLEAR_KEY = '$__last_clear_time$_';
const CLEAR_INTERVAL = 86400 * 3 * 1000; // 3 天扫一次过期项
const CLEAR_TICK = 60 * 15 * 1000; // 每 15 分钟检查一次

function fixPath(path: string) {
    if (path.startsWith('file:///')) return path.substring(7);
    if (path.startsWith('file:/')) return path.replace(/^file:\//, '/');
    return path;
}

export type KVDB = MMKV & {
    getObject: <T = any>(key: string) => T | undefined;
    setObject: (key: string, value: any, ttlSeconds: number) => void;
};

function attachObjectMethods(mmkv: MMKV): KVDB {
    const db = mmkv as KVDB;
    db.setObject = (key, value, ttlSeconds) => {
        db.set(
            key,
            JSON.stringify({ [TTL_KEY]: Date.now() + ttlSeconds * 1000, v: value })
        );
    };
    db.getObject = <T>(key: string) => {
        const raw = db.getString(key);
        if (!raw) return undefined;
        try {
            const obj = JSON.parse(raw) as { [TTL_KEY]: number; v: T };
            if (Date.now() > obj[TTL_KEY]) {
                db.remove(key);
                return undefined;
            }
            return obj.v;
        } catch {
            db.remove(key);
            return undefined;
        }
    };
    return db;
}

function makeStore(id: string) {
    let instance: KVDB | null = null;
    return () => {
        if (!instance) {
            instance = attachObjectMethods(
                createMMKV({ id, path: fixPath(fs.cacheDirectory ?? '') })
            );
        }
        return instance;
    };
}

export const getGlobalStorage = makeStore('global');
export const getCaches = makeStore('caches');
export const getApiCache = makeStore('api_cache');

// 启动后定期扫一遍缓存，清理过期项
setTimeout(() => {
    const tick = () => {
        const global = getGlobalStorage();
        const last = parseInt(global.getString(LAST_CLEAR_KEY) || '0', 10);
        const now = Date.now();
        if (now - last < CLEAR_INTERVAL) return;
        for (const db of [getCaches(), getApiCache(), global]) {
            for (const key of db.getAllKeys()) db.getObject(key);
        }
        global.set(LAST_CLEAR_KEY, now);
    };
    tick();
    setInterval(tick, CLEAR_TICK);
}, 3000);
