/**
 * JIRA Permission Gate
 *
 * Validates that sync permissions are enabled before allowing JIRA write operations.
 * This ensures manual JIRA commands respect the same permission settings as the
 * sync-coordinator.
 *
 * Usage:
 * ```typescript
 * const gate = await createJiraPermissionGate();
 * const result = gate.checkWritePermission();
 * if (!result.allowed) {
 *   console.log(result.reason);
 *   return;
 * }
 * ```
 *
 * @module jira-permission-gate
 */
import { promises as fs } from 'node:fs';
import * as path from 'node:path';
/**
 * Resolve preset permissions for fallback when explicit settings are absent
 */
function resolvePresetPermissions(preset) {
    switch (preset) {
        case 'bidirectional': return { canUpsert: true, canUpdateStatus: true };
        case 'push-only': return { canUpsert: true, canUpdateStatus: true };
        case 'full-control': return { canUpsert: true, canUpdateStatus: true };
        case 'read-only': return { canUpsert: false, canUpdateStatus: false };
        default: return { canUpsert: false, canUpdateStatus: false };
    }
}
/**
 * Default settings (all disabled for safety)
 */
export const DEFAULT_SYNC_SETTINGS = {
    canUpsertInternalItems: false,
    canUpdateExternalItems: false,
    canUpdateStatus: false,
};
/**
 * JIRA Permission Gate
 *
 * Checks permission settings before allowing JIRA write operations.
 */
export class JiraPermissionGate {
    constructor(settings, configPath) {
        this.settings = settings;
        this.configPath = configPath;
    }
    /**
     * Check if write operations (create/update issues) are allowed
     *
     * Requires: canUpdateExternalItems = true
     */
    checkWritePermission() {
        if (this.settings.canUpdateExternalItems) {
            return {
                allowed: true,
                reason: 'Write operations permitted (canUpdateExternalItems=true)',
            };
        }
        return {
            allowed: false,
            reason: 'Permission denied: JIRA updates are disabled.',
            suggestedAction: `Enable sync.settings.canUpdateExternalItems in ${this.configPath}`,
            settingPath: 'sync.settings.canUpdateExternalItems',
        };
    }
    /**
     * Check if status updates (transitions) are allowed
     *
     * Requires: canUpdateStatus = true
     */
    checkStatusPermission() {
        if (this.settings.canUpdateStatus) {
            return {
                allowed: true,
                reason: 'Status updates permitted (canUpdateStatus=true)',
            };
        }
        return {
            allowed: false,
            reason: 'Permission denied: JIRA status transitions are disabled.',
            suggestedAction: `Enable sync.settings.canUpdateStatus in ${this.configPath}`,
            settingPath: 'sync.settings.canUpdateStatus',
        };
    }
    /**
     * Check if internal item creation is allowed
     *
     * Requires: canUpsertInternalItems = true
     */
    checkCreateInternalPermission() {
        if (this.settings.canUpsertInternalItems) {
            return {
                allowed: true,
                reason: 'Internal item creation permitted (canUpsertInternalItems=true)',
            };
        }
        return {
            allowed: false,
            reason: 'Permission denied: Creating internal items is disabled.',
            suggestedAction: `Enable sync.settings.canUpsertInternalItems in ${this.configPath}`,
            settingPath: 'sync.settings.canUpsertInternalItems',
        };
    }
    /**
     * Check if close operation is allowed (requires both write AND status)
     *
     * Requires: canUpdateExternalItems = true AND canUpdateStatus = true
     */
    checkClosePermission() {
        const writeCheck = this.checkWritePermission();
        const statusCheck = this.checkStatusPermission();
        if (writeCheck.allowed && statusCheck.allowed) {
            return {
                allowed: true,
                reason: 'Close operations permitted (canUpdateExternalItems=true, canUpdateStatus=true)',
            };
        }
        const missingPermissions = [];
        if (!writeCheck.allowed) {
            missingPermissions.push('canUpdateExternalItems');
        }
        if (!statusCheck.allowed) {
            missingPermissions.push('canUpdateStatus');
        }
        return {
            allowed: false,
            reason: `Permission denied: Closing JIRA issues requires ${missingPermissions.join(' and ')}.`,
            suggestedAction: `Enable ${missingPermissions.map(p => `sync.settings.${p}`).join(' and ')} in ${this.configPath}`,
            settingPath: missingPermissions.map(p => `sync.settings.${p}`).join(', '),
        };
    }
    /**
     * Get current settings
     */
    getSettings() {
        return { ...this.settings };
    }
    /**
     * Get human-readable permission summary
     */
    getPermissionSummary() {
        const parts = [];
        if (this.settings.canUpdateExternalItems) {
            parts.push('create/update JIRA issues');
        }
        if (this.settings.canUpdateStatus) {
            parts.push('transition issue status');
        }
        if (this.settings.canUpsertInternalItems) {
            parts.push('create internal items');
        }
        if (parts.length === 0) {
            return 'All JIRA write operations disabled (read-only mode)';
        }
        return `Allowed: ${parts.join(', ')}`;
    }
}
/**
 * Create a JiraPermissionGate from config.json
 *
 * @param projectRoot - Project root directory (defaults to cwd)
 * @returns JiraPermissionGate instance
 */
export async function createJiraPermissionGate(projectRoot = process.cwd()) {
    const configPath = path.join(projectRoot, '.specweave', 'config.json');
    try {
        const content = await fs.readFile(configPath, 'utf-8');
        const config = JSON.parse(content);
        // v1.0.240 FIX: Honor preset (e.g., "bidirectional") when explicit settings absent
        const preset = config?.sync?.preset;
        const presetDefaults = resolvePresetPermissions(preset);
        const settings = {
            canUpsertInternalItems: config?.sync?.settings?.canUpsertInternalItems ?? false,
            canUpdateExternalItems: config?.sync?.settings?.canUpdateExternalItems ?? presetDefaults.canUpsert,
            canUpdateStatus: config?.sync?.settings?.canUpdateStatus ?? presetDefaults.canUpdateStatus,
        };
        return new JiraPermissionGate(settings, configPath);
    }
    catch {
        // Return gate with default (disabled) settings if config not found
        return new JiraPermissionGate(DEFAULT_SYNC_SETTINGS, configPath);
    }
}
/**
 * Quick check: Are JIRA write operations allowed?
 *
 * Convenience function for simple permission checks.
 *
 * @param projectRoot - Project root directory
 * @returns Permission check result
 */
export async function canWriteToJira(projectRoot = process.cwd()) {
    const gate = await createJiraPermissionGate(projectRoot);
    return gate.checkWritePermission();
}
/**
 * Quick check: Are JIRA status updates allowed?
 *
 * @param projectRoot - Project root directory
 * @returns Permission check result
 */
export async function canUpdateJiraStatus(projectRoot = process.cwd()) {
    const gate = await createJiraPermissionGate(projectRoot);
    return gate.checkStatusPermission();
}
/**
 * Quick check: Can JIRA issues be closed?
 *
 * @param projectRoot - Project root directory
 * @returns Permission check result
 */
export async function canCloseJiraIssue(projectRoot = process.cwd()) {
    const gate = await createJiraPermissionGate(projectRoot);
    return gate.checkClosePermission();
}
export default JiraPermissionGate;
//# sourceMappingURL=jira-permission-gate.js.map