/**
 * Git-Pinned Plugin Marketplace
 *
 * Manages plugins pinned to specific Git commit SHAs for reproducible
 * and auditable plugin installations.
 */
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { logger } from '../utils/logger.js';
// ============================================================================
// GitPinnedMarketplace
// ============================================================================
let instance = null;
export class GitPinnedMarketplace {
    plugins = new Map();
    configPath;
    constructor(configDir) {
        const dir = configDir || path.join(os.homedir(), '.codebuddy', 'plugins', 'git-pinned');
        this.configPath = path.join(dir, 'plugins.json');
        this.loadFromDisk();
    }
    static getInstance(configDir) {
        if (!instance) {
            instance = new GitPinnedMarketplace(configDir);
        }
        return instance;
    }
    static resetInstance() {
        instance = null;
    }
    loadFromDisk() {
        try {
            if (fs.existsSync(this.configPath)) {
                const data = JSON.parse(fs.readFileSync(this.configPath, 'utf-8'));
                if (Array.isArray(data)) {
                    for (const plugin of data) {
                        this.plugins.set(plugin.name, plugin);
                    }
                }
            }
        }
        catch (err) {
            logger.warn('Failed to load git-pinned plugins', { error: err });
        }
    }
    saveToDisk() {
        try {
            const dir = path.dirname(this.configPath);
            if (!fs.existsSync(dir)) {
                fs.mkdirSync(dir, { recursive: true });
            }
            fs.writeFileSync(this.configPath, JSON.stringify(Array.from(this.plugins.values()), null, 2));
        }
        catch (err) {
            logger.warn('Failed to save git-pinned plugins', { error: err });
        }
    }
    /**
     * Parse repo spec like "org/repo" or "org/repo@sha"
     */
    parseRepoSpec(repoSpec) {
        const atIndex = repoSpec.indexOf('@');
        let repoPath;
        let sha;
        if (atIndex !== -1) {
            repoPath = repoSpec.substring(0, atIndex);
            sha = repoSpec.substring(atIndex + 1);
        }
        else {
            repoPath = repoSpec;
        }
        const parts = repoPath.split('/');
        if (parts.length !== 2 || !parts[0] || !parts[1]) {
            throw new Error(`Invalid repo spec: ${repoSpec}. Expected format: org/repo or org/repo@sha`);
        }
        return { org: parts[0], repo: parts[1], sha };
    }
    install(repoSpec) {
        const { org, repo, sha } = this.parseRepoSpec(repoSpec);
        const name = `${org}/${repo}`;
        const commitSha = sha || 'HEAD';
        const plugin = {
            name,
            repo: `https://github.com/${name}`,
            commitSha,
            installedAt: Date.now(),
            verified: false,
            commands: [],
            hooks: [],
            mcpServers: [],
        };
        this.plugins.set(name, plugin);
        this.saveToDisk();
        logger.info(`Installed git-pinned plugin: ${name}@${commitSha}`);
        return plugin;
    }
    uninstall(name) {
        const existed = this.plugins.delete(name);
        if (existed) {
            this.saveToDisk();
            logger.info(`Uninstalled git-pinned plugin: ${name}`);
        }
        return existed;
    }
    list() {
        return Array.from(this.plugins.values());
    }
    verify(name) {
        const plugin = this.plugins.get(name);
        if (!plugin) {
            return false;
        }
        // In a real implementation, we would check the remote SHA
        // For now, mark as verified if SHA is not HEAD
        const isVerified = plugin.commitSha !== 'HEAD';
        plugin.verified = isVerified;
        this.saveToDisk();
        return isVerified;
    }
    update(name) {
        const plugin = this.plugins.get(name);
        if (!plugin) {
            return null;
        }
        // Simulate updating to a new SHA
        plugin.commitSha = `updated-${Date.now().toString(16)}`;
        plugin.verified = false;
        plugin.installedAt = Date.now();
        this.saveToDisk();
        logger.info(`Updated git-pinned plugin: ${name}`);
        return plugin;
    }
    getPlugin(name) {
        return this.plugins.get(name);
    }
    getTrustWarning(repo) {
        return `WARNING: Plugin from '${repo}' is not verified. ` +
            'Unverified plugins may contain malicious code. ' +
            'Review the source code and pin to a specific commit SHA before using.';
    }
    isInstalled(name) {
        return this.plugins.has(name);
    }
}
export function getGitPinnedMarketplace(configDir) {
    return GitPinnedMarketplace.getInstance(configDir);
}
export function resetGitPinnedMarketplace() {
    GitPinnedMarketplace.resetInstance();
}
//# sourceMappingURL=git-pinned-marketplace.js.map