// @ts-nocheck
import * as quark_api from "./quark-api";

/**
 * 容量信息 & 空间清理模块。
 */
const BASE_URL = 'https://drive-pc.quark.cn';
// ==================== Storage Info ====================
/** Cached used space, keyed by hour block (3h window) */
const cachedUsedSpace = null;
// We use a function-scoped cache instead of instance field
const storageCache = { bytes: 0, hourBlock: -1 };
/**
 * Get total capacity from /capacity/detail API.
 * Also does a quick used-space estimate by summing root-level file sizes + subdir sizes
 * (夸克目录的 size 字段 = 该目录内所有文件总大小，无需递归).
 * If the API fails (e.g. missing sign params), falls back to fallbackTotal if provided.
 */
export async function getStorageInfoQuick(cookie, fallbackTotal) {
    try {
        const params = new URLSearchParams(quark_api.getCommonParams());
        const capResponse = await fetch(`${BASE_URL}/1/clouddrive/capacity/detail?${params.toString()}`, {
            headers: quark_api.getHeaders(cookie),
            signal: AbortSignal.timeout(10000),
        });
        let totalBytes = 0;
        if (capResponse.ok) {
            const data = await capResponse.json();
            if (data.status === 200 && data.data) {
                totalBytes = data.data.capacity_summary?.sum_capacity || 0;
                if (totalBytes === 0) {
                    const memberships = [...(data.data.effect || []), ...(data.data.expired || [])];
                    totalBytes = memberships.reduce((max, m) => Math.max(max, m.capacity || 0), 0);
                }
            }
        }
        // Accurate used space via /member API (1 call, no full traversal needed)
        // Ref: pan.quark.cn/1/clouddrive/member returns use_capacity + total_capacity
        let usedBytes = 0;
        try {
            const memberParams = new URLSearchParams({ pr: 'ucpro', fr: 'pc', uc_param_str: '', __t: String(Date.now()), __dt: '1000' });
            const memberResp = await fetch(`https://pan.quark.cn/1/clouddrive/member?${memberParams.toString()}`, {
                headers: quark_api.getHeaders(cookie),
                signal: AbortSignal.timeout(10000),
            });
            if (memberResp.ok) {
                const memberData = await memberResp.json();
                if (memberData.status === 200 && memberData.data?.use_capacity != null) {
                    usedBytes = memberData.data.use_capacity;
                }
            }
        }
        catch { }
        // Fallback: sum root-level file sizes (夸克 folders return size=0)
        if (usedBytes === 0) {
            try {
                const rootFiles = await quark_api.listRootDir(cookie);
                for (const f of rootFiles) {
                    usedBytes += f.size || 0;
                }
            }
            catch { }
        }
        // Cache the result (3h window)
        const currentHourBlock = Math.floor(new Date().getHours() / 3);
        storageCache.bytes = usedBytes;
        storageCache.hourBlock = currentHourBlock;
        if (totalBytes > 0) {
            return {
                total: quark_api.formatBytes(totalBytes),
                totalBytes,
                used: quark_api.formatBytes(usedBytes),
                usedBytes,
            };
        }
    }
    catch { }
    // Fallback: try to parse from a human-readable string like "6 TB"
    if (fallbackTotal) {
        const match = fallbackTotal.match(/^([\d.]+)\s*([KMGT]B?)/i);
        if (match) {
            const num = parseFloat(match[1]);
            const unit = match[2].toUpperCase();
            const multipliers = { B: 1, KB: 1024, MB: 1024 ** 2, GB: 1024 ** 3, TB: 1024 ** 4, PB: 1024 ** 5 };
            const multiplier = multipliers[unit] || multipliers[unit.replace('B', '') + 'B'] || 0;
            if (multiplier > 0) {
                return { total: fallbackTotal, totalBytes: Math.round(num * multiplier), used: '-', usedBytes: 0 };
            }
        }
    }
    return { total: '-', totalBytes: 0, used: '-', usedBytes: 0 };
}
/**
 * Get storage info with used space calculation.
 */
/**
 * Fast estimation (root-level files only) + background full traversal.
 * First call returns quickly; full traversal runs async and updates DB later.
 * `onBackgroundComplete` is called when traversal finishes.
 */
export async function getStorageInfo(cookie, onBackgroundComplete) {
    try {
        const params = new URLSearchParams(quark_api.getCommonParams());
        const response = await fetch(`${BASE_URL}/1/clouddrive/capacity/detail?${params.toString()}`, {
            headers: quark_api.getHeaders(cookie),
            signal: AbortSignal.timeout(10000),
        });
        let totalBytes = 0;
        if (response.ok) {
            const data = await response.json();
            if (data.status === 200 && data.data) {
                totalBytes = data.data.capacity_summary?.sum_capacity || 0;
                if (totalBytes === 0) {
                    const memberships = [...(data.data.effect || []), ...(data.data.expired || [])];
                    totalBytes = memberships.reduce((max, m) => Math.max(max, m.capacity || 0), 0);
                }
            }
        }
        const totalFormatted = totalBytes > 0 ? quark_api.formatBytes(totalBytes) : '-';
        // Quick estimation: sum root-level files only
        let quickUsed = 0;
        try {
            const rootFiles = await quark_api.listRootDir(cookie);
            for (const f of rootFiles) {
                quickUsed += f.size || 0;
            }
        }
        catch { }
        // Budget full traversal in background (no await)
        calculateUsedSpace(cookie).then(fullUsed => {
            if (onBackgroundComplete) {
                onBackgroundComplete(quark_api.formatBytes(fullUsed), totalFormatted);
            }
        }).catch(err => {
            console.error('[Storage] Background full traversal failed:', err.message);
        });
        return {
            total: totalFormatted,
            totalBytes,
            used: quark_api.formatBytes(quickUsed),
            usedBytes: quickUsed,
        };
    }
    catch {
        return { used: '-', total: '-', usedBytes: 0, totalBytes: 0 };
    }
}
/**
 * Calculate total used space by recursively traversing all files
 * and summing their sizes. Uses 3-hour time window cache.
 */
export async function calculateUsedSpace(cookie) {
    const currentHourBlock = Math.floor(new Date().getHours() / 3);
    if (storageCache.hourBlock === currentHourBlock && storageCache.bytes > 0) {
        return storageCache.bytes;
    }
    let totalUsed = 0;
    const stack = ['0'];
    const visited = new Set();
    while (stack.length > 0) {
        const fid = stack.pop();
        if (visited.has(fid))
            continue;
        visited.add(fid);
        const files = await quark_api.listDirAllPages(cookie, fid);
        if (!files.length)
            continue;
        for (const f of files) {
            if (f.dir) {
                stack.push(f.fid);
            }
            else {
                totalUsed += f.size || 0;
            }
        }
        await new Promise(r => setTimeout(r, 50));
    }
    storageCache.bytes = totalUsed;
    storageCache.hourBlock = currentHourBlock;
    return totalUsed;
}
// ==================== Cleanup ====================
/**
 * Trash specified files/folders (move to recycle bin).
 */
export async function trashFiles(cookie, fids) {
    if (!fids.length)
        return true;
    try {
        const response = await fetch(`${BASE_URL}/1/clouddrive/file/trash?${quark_api.makeQuery()}`, {
            method: 'POST',
            headers: { ...quark_api.getHeaders(cookie), 'Content-Type': 'application/json' },
            body: JSON.stringify({
                action_type: 1, // 1 = move to trash
                filelist: fids,
                exclude_filelist: [],
            }),
            signal: AbortSignal.timeout(30000),
        });
        if (!response.ok)
            return false;
        const data = await response.json();
        if (data.status === 200)
            return true;
        console.error(`[Quark] trashFiles failed: ${data.message || data.status}`);
        return false;
    }
    catch (err) {
        console.error(`[Quark] trashFiles error: ${err.message}`);
        return false;
    }
}
/**
 * Empty the recycle bin — permanently delete all files in trash.
 */
export async function emptyTrash(cookie) {
    try {
        const response = await fetch(`${BASE_URL}/1/clouddrive/file/trash/clear?${quark_api.makeQuery()}`, {
            method: 'POST',
            headers: { ...quark_api.getHeaders(cookie), 'Content-Type': 'application/json' },
            body: JSON.stringify({}),
            signal: AbortSignal.timeout(60000),
        });
        if (!response.ok)
            return false;
        const data = await response.json();
        if (data.status === 200)
            return true;
        console.error(`[Quark] emptyTrash failed: ${data.message || data.status}`);
        return false;
    }
    catch (err) {
        console.error(`[Quark] emptyTrash error: ${err.message}`);
        return false;
    }
}
/**
 * Cleanup: trash date-named folders (YYYY-MM-DD) older than `days`.
 */
export async function cleanupOldDateFolders(cookie, days, whitelistDirs) {
    const errors = [];
    const cutoff = new Date();
    cutoff.setDate(cutoff.getDate() - days);
    const cutoffStr = cutoff.toISOString().slice(0, 10);
    try {
        const rootItems = await quark_api.listRootDir(cookie);
        const oldFolders = rootItems.filter(item => {
            if (!item.dir)
                return false;
            if (!/^\d{4}-\d{2}-\d{2}$/.test(item.file_name))
                return false;
            if (whitelistDirs && whitelistDirs.includes(item.file_name))
                return false;
            return item.file_name < cutoffStr;
        });
        if (oldFolders.length === 0) {
            return { trashed: 0, errors: [] };
        }
        const fids = oldFolders.map(f => f.fid);
        console.log(`[Quark] Trashing ${fids.length} old date folders (before ${cutoffStr}): ${oldFolders.map(f => f.file_name).join(', ')}`);
        const ok = await trashFiles(cookie, fids);
        if (ok) {
            return { trashed: fids.length, errors: [] };
        }
        return { trashed: 0, errors: [`Trash API returned failure for ${fids.length} folders`] };
    }
    catch (err) {
        return { trashed: 0, errors: [err.message] };
    }
}
/**
 * Cleanup: if used space exceeds thresholdPercent% of total,
 * delete the oldest date folders until totalBytes * deletePercent/100
 * of total capacity is freed.
 */
export async function cleanupBySpaceThreshold(cookie, thresholdPercent, deletePercent, whitelistDirs) {
    const errors = [];
    try {
        const storage = await getStorageInfo(cookie);
        if (storage.totalBytes <= 0)
            return { trashed: 0, errors: [] };
        const usagePercent = (storage.usedBytes / storage.totalBytes) * 100;
        if (usagePercent < thresholdPercent) {
            console.log(`[Quark] Usage ${usagePercent.toFixed(1)}% below threshold ${thresholdPercent}%, skipping`);
            return { trashed: 0, errors: [] };
        }
        const targetBytesToFree = Math.floor(storage.totalBytes * Math.min(deletePercent, 100) / 100);
        const rootItems = await quark_api.listRootDir(cookie);
        const dateFolders = rootItems
            .filter(item => item.dir && /^\d{4}-\d{2}-\d{2}$/.test(item.file_name))
            .filter(item => !whitelistDirs || !whitelistDirs.includes(item.file_name))
            .sort((a, b) => a.file.localeCompare(b.file_name));
        if (dateFolders.length === 0)
            return { trashed: 0, errors: [] };
        const hasSizes = dateFolders.some(f => f.size && f.size > 0);
        let cumulativeSize = 0;
        const foldersToTrash = [];
        if (hasSizes) {
            for (const folder of dateFolders) {
                foldersToTrash.push(folder);
                cumulativeSize += folder.size || 0;
                if (cumulativeSize >= targetBytesToFree)
                    break;
            }
        }
        else {
            const avgSizePerFolder = storage.usedBytes / dateFolders.length;
            const estCount = Math.max(1, Math.ceil(targetBytesToFree / avgSizePerFolder));
            foldersToTrash.push(...dateFolders.slice(0, estCount));
            cumulativeSize = estCount * avgSizePerFolder;
        }
        const freedMB = (cumulativeSize / 1024 / 1024).toFixed(0);
        const targetMB = (targetBytesToFree / 1024 / 1024).toFixed(0);
        const fidsToTrash = foldersToTrash.map(f => f.fid);
        console.log(`[Quark] Space threshold: trashing ${foldersToTrash.length}/${dateFolders.length} oldest folders (~${freedMB} MB) to free ${targetMB} MB (${deletePercent}% of ${(storage.totalBytes / 1024 / 1024 / 1024).toFixed(0)} GB total)`);
        const ok = await trashFiles(cookie, fidsToTrash);
        if (ok) {
            console.log(`[Quark] ✅ Space-threshold trashed ${foldersToTrash.length} folders (~${freedMB} MB)`);
            return { trashed: foldersToTrash.length, errors: [] };
        }
        return { trashed: 0, errors: [`Space-threshold trash failed for ${foldersToTrash.length} folders`] };
    }
    catch (err) {
        return { trashed: 0, errors: [err.message] };
    }
}
