import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, unlinkSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
// Manifest directory location
const MANIFEST_DIR = join(homedir(), '.claude-manifests');
/**
 * Ensure manifest directory exists
 */
function ensureManifestDir() {
    if (!existsSync(MANIFEST_DIR)) {
        mkdirSync(MANIFEST_DIR, { recursive: true });
    }
}
/**
 * Create a new installation manifest
 * @param mode - Installation mode (Global/Path)
 * @param installPath - Installation path
 * @returns New manifest object
 */
export function createManifest(mode, installPath) {
    ensureManifestDir();
    const timestamp = new Date().toISOString().replace(/[-:]/g, '').replace('T', '-').split('.')[0];
    const modePrefix = mode === 'Global' ? 'manifest-global' : 'manifest-path';
    const manifestId = `${modePrefix}-${timestamp}`;
    return {
        manifest_id: manifestId,
        version: '1.0',
        installation_mode: mode,
        installation_path: installPath,
        installation_date: new Date().toISOString(),
        installer_version: '1.0.0',
        files: [],
        directories: []
    };
}
/**
 * Add file entry to manifest
 * @param manifest - Manifest object
 * @param filePath - File path
 */
export function addFileEntry(manifest, filePath) {
    manifest.files.push({
        path: filePath,
        type: 'File',
        timestamp: new Date().toISOString()
    });
}
/**
 * Add directory entry to manifest
 * @param manifest - Manifest object
 * @param dirPath - Directory path
 */
export function addDirectoryEntry(manifest, dirPath) {
    manifest.directories.push({
        path: dirPath,
        type: 'Directory',
        timestamp: new Date().toISOString()
    });
}
/**
 * Save manifest to disk
 * @param manifest - Manifest object
 * @returns Path to saved manifest
 */
export function saveManifest(manifest) {
    ensureManifestDir();
    // Remove old manifests for same path and mode
    removeOldManifests(manifest.installation_path, manifest.installation_mode);
    const manifestPath = join(MANIFEST_DIR, `${manifest.manifest_id}.json`);
    writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
    return manifestPath;
}
/**
 * Remove old manifests for the same installation path and mode
 * @param installPath - Installation path
 * @param mode - Installation mode
 */
function removeOldManifests(installPath, mode) {
    if (!existsSync(MANIFEST_DIR))
        return;
    const normalizedPath = installPath.toLowerCase().replace(/[\\/]+$/, '');
    try {
        const files = readdirSync(MANIFEST_DIR).filter(f => f.endsWith('.json'));
        for (const file of files) {
            try {
                const filePath = join(MANIFEST_DIR, file);
                const content = JSON.parse(readFileSync(filePath, 'utf8'));
                const manifestPath = (content.installation_path || '').toLowerCase().replace(/[\\/]+$/, '');
                const manifestMode = content.installation_mode || 'Global';
                if (manifestPath === normalizedPath && manifestMode === mode) {
                    unlinkSync(filePath);
                }
            }
            catch {
                // Skip invalid manifest files
            }
        }
    }
    catch {
        // Ignore errors
    }
}
/**
 * Get all installation manifests
 * @returns Array of manifest objects
 */
export function getAllManifests() {
    if (!existsSync(MANIFEST_DIR))
        return [];
    const manifests = [];
    try {
        const files = readdirSync(MANIFEST_DIR).filter(f => f.endsWith('.json'));
        for (const file of files) {
            try {
                const filePath = join(MANIFEST_DIR, file);
                const content = JSON.parse(readFileSync(filePath, 'utf8'));
                // Try to read version.json for application version
                let appVersion = 'unknown';
                try {
                    const versionPath = join(content.installation_path, '.claude', 'version.json');
                    if (existsSync(versionPath)) {
                        const versionInfo = JSON.parse(readFileSync(versionPath, 'utf8'));
                        appVersion = versionInfo.version || 'unknown';
                    }
                }
                catch {
                    // Ignore
                }
                manifests.push({
                    ...content,
                    manifest_file: filePath,
                    application_version: appVersion,
                    files_count: content.files?.length || 0,
                    directories_count: content.directories?.length || 0
                });
            }
            catch {
                // Skip invalid manifest files
            }
        }
        // Sort by installation date (newest first)
        manifests.sort((a, b) => new Date(b.installation_date).getTime() - new Date(a.installation_date).getTime());
    }
    catch {
        // Ignore errors
    }
    return manifests;
}
/**
 * Find manifest for a specific path and mode
 * @param installPath - Installation path
 * @param mode - Installation mode
 * @returns Manifest or null
 */
export function findManifest(installPath, mode) {
    const manifests = getAllManifests();
    const normalizedPath = installPath.toLowerCase().replace(/[\\/]+$/, '');
    return manifests.find(m => {
        const manifestPath = (m.installation_path || '').toLowerCase().replace(/[\\/]+$/, '');
        return manifestPath === normalizedPath && m.installation_mode === mode;
    }) || null;
}
/**
 * Delete a manifest file
 * @param manifestFile - Path to manifest file
 */
export function deleteManifest(manifestFile) {
    if (existsSync(manifestFile)) {
        unlinkSync(manifestFile);
    }
}
/**
 * Get manifest directory path
 * @returns Manifest directory path
 */
export function getManifestDir() {
    return MANIFEST_DIR;
}
/**
 * Get file reference counts across all manifests
 * Returns a map of file path -> array of manifest IDs that reference it
 * @param excludeManifestId - Optional manifest ID to exclude from counting
 * @returns Map of file paths to referencing manifest IDs
 */
export function getFileReferenceCounts(excludeManifestId) {
    const fileRefs = new Map();
    const manifests = getAllManifests();
    for (const manifest of manifests) {
        // Skip the excluded manifest (usually the one being replaced)
        if (excludeManifestId && manifest.manifest_id === excludeManifestId) {
            continue;
        }
        for (const fileEntry of manifest.files || []) {
            const normalizedPath = fileEntry.path.toLowerCase().replace(/\\/g, '/');
            const refs = fileRefs.get(normalizedPath) || [];
            refs.push(manifest.manifest_id);
            fileRefs.set(normalizedPath, refs);
        }
    }
    return fileRefs;
}
/**
 * Check if a file is referenced by other installations
 * @param filePath - File path to check
 * @param excludeManifestId - Manifest ID to exclude from checking
 * @returns True if file is referenced by other installations
 */
export function isFileReferencedByOthers(filePath, excludeManifestId) {
    const fileRefs = getFileReferenceCounts(excludeManifestId);
    const normalizedPath = filePath.toLowerCase().replace(/\\/g, '/');
    const refs = fileRefs.get(normalizedPath) || [];
    return refs.length > 0;
}
//# sourceMappingURL=manifest.js.map