import { readJson, writeJson, projectDataDir } from './base-store.js';
import { mkdir, cp, rm, readdir, stat } from 'node:fs/promises';
import { join } from 'node:path';
function trashDir(projectId) {
    return `${projectDataDir(projectId)}/.trash`;
}
function trashManifest(projectId) {
    return `${trashDir(projectId)}/manifest.json`;
}
/**
 * Ensure the .trash directory exists for a project.
 */
async function ensureTrashDir(projectId) {
    await mkdir(trashDir(projectId), { recursive: true });
}
/**
 * Load the trash manifest (list of all trashed items).
 */
export async function loadManifest(projectId) {
    return readJson(trashManifest(projectId), []);
}
/**
 * Save the trash manifest.
 */
async function saveManifest(projectId, items) {
    await writeJson(trashManifest(projectId), items);
}
/**
 * Move a directory to trash. Returns the TrashItem metadata.
 */
export async function moveToTrash(projectId, itemType, itemId, sourcePath, metadata) {
    await ensureTrashDir(projectId);
    const timestamp = Date.now();
    const trashSubdir = `${timestamp}-${itemType}-${itemId}`;
    const destPath = join(trashDir(projectId), trashSubdir);
    await cp(sourcePath, destPath, { recursive: true });
    await rm(sourcePath, { recursive: true, force: true });
    const item = {
        id: trashSubdir,
        itemType,
        originalPath: sourcePath,
        trashPath: destPath,
        deletedAt: new Date().toISOString(),
        metadata,
    };
    const manifest = await loadManifest(projectId);
    manifest.push(item);
    await saveManifest(projectId, manifest);
    return item;
}
/**
 * Move JSON data to trash (for patterns/decisions stored in JSON arrays).
 * Creates a JSON file in the trash directory with the item data.
 */
export async function moveDataToTrash(projectId, itemType, itemId, data, metadata) {
    await ensureTrashDir(projectId);
    const timestamp = Date.now();
    const trashSubdir = `${timestamp}-${itemType}-${itemId}`;
    const destPath = join(trashDir(projectId), trashSubdir);
    await mkdir(destPath, { recursive: true });
    await writeJson(join(destPath, 'data.json'), data);
    const item = {
        id: trashSubdir,
        itemType,
        originalPath: `${itemType}:${itemId}`,
        trashPath: destPath,
        deletedAt: new Date().toISOString(),
        metadata,
    };
    const manifest = await loadManifest(projectId);
    manifest.push(item);
    await saveManifest(projectId, manifest);
    return item;
}
/**
 * Restore an item from trash to its original location.
 */
export async function restoreFromTrash(projectId, trashItemId) {
    const manifest = await loadManifest(projectId);
    const idx = manifest.findIndex((i) => i.id === trashItemId);
    if (idx === -1) {
        return null;
    }
    const item = manifest[idx];
    /* v8 ignore next 3 -- unreachable: findIndex already validated idx */
    if (!item) {
        return null;
    }
    // Restore directory-based items
    if (!item.originalPath.includes(':')) {
        await mkdir(item.originalPath, { recursive: true });
        await cp(item.trashPath, item.originalPath, { recursive: true });
    }
    await rm(item.trashPath, { recursive: true, force: true });
    manifest.splice(idx, 1);
    await saveManifest(projectId, manifest);
    return item;
}
/**
 * Permanently remove a specific item from trash.
 */
export async function purgeTrashItem(projectId, trashItemId) {
    const manifest = await loadManifest(projectId);
    const idx = manifest.findIndex((i) => i.id === trashItemId);
    if (idx === -1) {
        return false;
    }
    const item = manifest[idx];
    /* v8 ignore next 3 -- unreachable: findIndex already validated idx */
    if (!item) {
        return false;
    }
    await rm(item.trashPath, { recursive: true, force: true });
    manifest.splice(idx, 1);
    await saveManifest(projectId, manifest);
    return true;
}
/**
 * Purge all items from trash.
 */
export async function purgeAllTrash(projectId) {
    const manifest = await loadManifest(projectId);
    const count = manifest.length;
    for (const item of manifest) {
        await rm(item.trashPath, { recursive: true, force: true });
    }
    await saveManifest(projectId, []);
    return count;
}
/**
 * Count files in a directory recursively (for project delete summary).
 */
export async function countFiles(dirPath) {
    try {
        const entries = await readdir(dirPath, { withFileTypes: true });
        let count = 0;
        for (const entry of entries) {
            if (entry.isDirectory()) {
                count += await countFiles(join(dirPath, entry.name));
            }
            else {
                count += 1;
            }
        }
        return count;
    }
    catch {
        return 0;
    }
}
/**
 * Check if a path exists.
 */
export async function pathExists(p) {
    try {
        await stat(p);
        return true;
    }
    catch {
        return false;
    }
}
// ---------------------------------------------------------------------------
// Trash TTL cleanup (SPEC-094 AC-6)
// ---------------------------------------------------------------------------
/**
 * Recursively sum file sizes in a directory.
 */
export async function getDirSize(dirPath) {
    try {
        const entries = await readdir(dirPath, { withFileTypes: true });
        let total = 0;
        for (const entry of entries) {
            const full = join(dirPath, entry.name);
            if (entry.isDirectory()) {
                total += await getDirSize(full);
            }
            else {
                const s = await stat(full);
                total += s.size;
            }
        }
        return total;
    }
    catch {
        return 0;
    }
}
/**
 * Auto-clean trash items that exceed age or total size limits.
 * Purges oldest items first. Lazy: call on trash operations.
 */
export async function autoCleanTrash(projectId, config = { maxAgeDays: 30, maxSizeMB: 1024 }) {
    const manifest = await loadManifest(projectId);
    if (manifest.length === 0) {
        return { purgedCount: 0, freedBytes: 0, remainingCount: 0 };
    }
    // Sort oldest first
    manifest.sort((a, b) => Date.parse(a.deletedAt) - Date.parse(b.deletedAt));
    let purgedCount = 0;
    let freedBytes = 0;
    const maxAgeMs = config.maxAgeDays * 86_400_000;
    const now = Date.now();
    // First pass — age
    const remaining = [];
    for (const item of manifest) {
        if (now - Date.parse(item.deletedAt) > maxAgeMs) {
            const size = await getDirSize(item.trashPath);
            await rm(item.trashPath, { recursive: true, force: true });
            freedBytes += size;
            purgedCount++;
        }
        else {
            remaining.push(item);
        }
    }
    // Second pass — size limit
    const maxBytes = config.maxSizeMB * 1024 * 1024;
    let totalSize = 0;
    for (const item of remaining) {
        totalSize += await getDirSize(item.trashPath);
    }
    while (totalSize > maxBytes && remaining.length > 0) {
        const oldest = remaining.shift();
        if (!oldest) {
            break;
        }
        const size = await getDirSize(oldest.trashPath);
        await rm(oldest.trashPath, { recursive: true, force: true });
        totalSize -= size;
        freedBytes += size;
        purgedCount++;
    }
    await saveManifest(projectId, remaining);
    return { purgedCount, freedBytes, remainingCount: remaining.length };
}
//# sourceMappingURL=trash-store.js.map