/**
 * GitHub Actions Integration
 *
 * Enables AI-powered CI/CD workflow management:
 * - Create and manage GitHub Actions workflows
 * - AI-assisted workflow debugging
 * - Automated PR checks
 * - Security scanning in CI
 * - Cost optimization for workflows
 *
 * Inspired by Gemini CLI's GitHub integration.
 */
import { EventEmitter } from 'events';
import * as fs from 'fs';
import * as path from 'path';
import { spawn } from 'child_process';
import * as yaml from 'js-yaml';
// ============================================================================
// Workflow Templates
// ============================================================================
const WORKFLOW_TEMPLATES = {
    'node-ci': {
        name: 'Node.js CI',
        on: {
            push: { branches: ['main', 'develop'] },
            pull_request: { branches: ['main'] },
        },
        jobs: {
            build: {
                'runs-on': 'ubuntu-latest',
                strategy: {
                    matrix: {
                        'node-version': ['18.x', '20.x', '22.x'],
                    },
                },
                steps: [
                    { uses: 'actions/checkout@v4' },
                    {
                        name: 'Use Node.js ${{ matrix.node-version }}',
                        uses: 'actions/setup-node@v4',
                        with: { 'node-version': '${{ matrix.node-version }}', cache: 'npm' },
                    },
                    { run: 'npm ci' },
                    { run: 'npm run build --if-present' },
                    { run: 'npm test' },
                ],
            },
        },
    },
    'python-ci': {
        name: 'Python CI',
        on: {
            push: { branches: ['main'] },
            pull_request: { branches: ['main'] },
        },
        jobs: {
            build: {
                'runs-on': 'ubuntu-latest',
                strategy: {
                    matrix: {
                        'python-version': ['3.10', '3.11', '3.12'],
                    },
                },
                steps: [
                    { uses: 'actions/checkout@v4' },
                    {
                        name: 'Set up Python ${{ matrix.python-version }}',
                        uses: 'actions/setup-python@v5',
                        with: { 'python-version': '${{ matrix.python-version }}' },
                    },
                    {
                        name: 'Install dependencies',
                        run: 'python -m pip install --upgrade pip\npip install -r requirements.txt',
                    },
                    {
                        name: 'Run tests',
                        run: 'pytest',
                    },
                ],
            },
        },
    },
    'security-scan': {
        name: 'Security Scan',
        on: {
            push: { branches: ['main'] },
            pull_request: { branches: ['main'] },
            schedule: [{ cron: '0 0 * * 0' }],
        },
        jobs: {
            'security-scan': {
                'runs-on': 'ubuntu-latest',
                steps: [
                    { uses: 'actions/checkout@v4' },
                    {
                        name: 'Run Trivy vulnerability scanner',
                        uses: 'aquasecurity/trivy-action@master',
                        with: {
                            'scan-type': 'fs',
                            'ignore-unfixed': true,
                            format: 'sarif',
                            output: 'trivy-results.sarif',
                        },
                    },
                    {
                        name: 'Upload Trivy scan results',
                        uses: 'github/codeql-action/upload-sarif@v3',
                        with: { 'sarif_file': 'trivy-results.sarif' },
                    },
                ],
            },
        },
    },
    'release': {
        name: 'Release',
        on: {
            push: { tags: ['v*'] },
        },
        jobs: {
            release: {
                'runs-on': 'ubuntu-latest',
                steps: [
                    { uses: 'actions/checkout@v4' },
                    {
                        name: 'Create Release',
                        uses: 'softprops/action-gh-release@v2',
                        with: {
                            generate_release_notes: true,
                        },
                        env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' },
                    },
                ],
            },
        },
    },
    'docker-build': {
        name: 'Docker Build',
        on: {
            push: { branches: ['main'], tags: ['v*'] },
            pull_request: { branches: ['main'] },
        },
        jobs: {
            build: {
                'runs-on': 'ubuntu-latest',
                steps: [
                    { uses: 'actions/checkout@v4' },
                    {
                        name: 'Set up Docker Buildx',
                        uses: 'docker/setup-buildx-action@v3',
                    },
                    {
                        name: 'Login to GitHub Container Registry',
                        uses: 'docker/login-action@v3',
                        with: {
                            registry: 'ghcr.io',
                            username: '${{ github.actor }}',
                            password: '${{ secrets.GITHUB_TOKEN }}',
                        },
                    },
                    {
                        name: 'Build and push',
                        uses: 'docker/build-push-action@v5',
                        with: {
                            push: '${{ github.event_name != \'pull_request\' }}',
                            tags: 'ghcr.io/${{ github.repository }}:latest',
                            cache_from: 'type=gha',
                            cache_to: 'type=gha,mode=max',
                        },
                    },
                ],
            },
        },
    },
    'lint-format': {
        name: 'Lint and Format',
        on: {
            push: { branches: ['main'] },
            pull_request: { branches: ['main'] },
        },
        jobs: {
            lint: {
                'runs-on': 'ubuntu-latest',
                steps: [
                    { uses: 'actions/checkout@v4' },
                    { uses: 'actions/setup-node@v4', with: { 'node-version': '20', cache: 'npm' } },
                    { run: 'npm ci' },
                    { name: 'Run ESLint', run: 'npm run lint' },
                    { name: 'Check formatting', run: 'npm run format:check || npm run format -- --check' },
                    { name: 'Type check', run: 'npm run typecheck || npm run type-check || true' },
                ],
            },
        },
    },
    'grok-review': {
        name: 'CodeBuddy AI Review',
        on: {
            pull_request: { types: ['opened', 'synchronize'] },
        },
        jobs: {
            review: {
                'runs-on': 'ubuntu-latest',
                steps: [
                    { uses: 'actions/checkout@v4', with: { 'fetch-depth': 0 } },
                    {
                        name: 'Install Code Buddy',
                        run: 'npm install -g code-buddy',
                    },
                    {
                        name: 'Run AI Review',
                        run: 'grok --non-interactive "Review the changes in this PR and provide feedback"',
                        env: {
                            GROK_API_KEY: '${{ secrets.GROK_API_KEY }}',
                        },
                    },
                ],
            },
        },
    },
};
// ============================================================================
// GitHub Actions Manager
// ============================================================================
export class GitHubActionsManager extends EventEmitter {
    config;
    workflowsDir;
    constructor(config = {}) {
        super();
        this.config = {
            workflowsDir: '.github/workflows',
            ...config,
        };
        this.workflowsDir = this.config.workflowsDir;
    }
    /**
     * Initialize and detect repository info
     */
    async initialize() {
        // Try to detect from git remote
        if (!this.config.owner || !this.config.repo) {
            try {
                const remote = await this.execGit(['remote', 'get-url', 'origin']);
                const match = remote.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
                if (match) {
                    this.config.owner = this.config.owner || match[1];
                    this.config.repo = this.config.repo || match[2];
                }
            }
            catch {
                // Ignore errors
            }
        }
        // Ensure workflows directory exists
        if (!fs.existsSync(this.workflowsDir)) {
            fs.mkdirSync(this.workflowsDir, { recursive: true });
        }
        this.emit('initialized');
    }
    /**
     * List available workflow templates
     */
    getTemplates() {
        return Object.keys(WORKFLOW_TEMPLATES);
    }
    /**
     * Get template details
     */
    getTemplate(name) {
        return WORKFLOW_TEMPLATES[name] || null;
    }
    /**
     * Create workflow from template
     */
    async createFromTemplate(templateName, fileName) {
        const template = WORKFLOW_TEMPLATES[templateName];
        if (!template) {
            throw new Error(`Unknown template: ${templateName}`);
        }
        const workflowFileName = fileName || `${templateName}.yml`;
        const workflowPath = path.join(this.workflowsDir, workflowFileName);
        // Check if file exists
        if (fs.existsSync(workflowPath)) {
            throw new Error(`Workflow file already exists: ${workflowPath}`);
        }
        // Write workflow
        const yamlContent = yaml.dump(template, { lineWidth: -1, noRefs: true });
        fs.writeFileSync(workflowPath, yamlContent);
        this.emit('workflow:created', { path: workflowPath, template: templateName });
        return workflowPath;
    }
    /**
     * Create custom workflow
     */
    async createWorkflow(config, fileName) {
        const workflowPath = path.join(this.workflowsDir, fileName);
        if (fs.existsSync(workflowPath)) {
            throw new Error(`Workflow file already exists: ${workflowPath}`);
        }
        const yamlContent = yaml.dump(config, { lineWidth: -1, noRefs: true });
        fs.writeFileSync(workflowPath, yamlContent);
        this.emit('workflow:created', { path: workflowPath });
        return workflowPath;
    }
    /**
     * List existing workflows
     */
    listWorkflows() {
        if (!fs.existsSync(this.workflowsDir)) {
            return [];
        }
        const files = fs.readdirSync(this.workflowsDir)
            .filter(f => f.endsWith('.yml') || f.endsWith('.yaml'));
        return files.map(file => {
            const filePath = path.join(this.workflowsDir, file);
            let config;
            try {
                const content = fs.readFileSync(filePath, 'utf-8');
                config = yaml.load(content);
            }
            catch {
                // Ignore parse errors
            }
            return {
                name: config?.name || file,
                path: filePath,
                config,
            };
        });
    }
    /**
     * Read workflow file
     */
    readWorkflow(fileName) {
        const workflowPath = path.join(this.workflowsDir, fileName);
        if (!fs.existsSync(workflowPath)) {
            return null;
        }
        try {
            const content = fs.readFileSync(workflowPath, 'utf-8');
            return yaml.load(content);
        }
        catch {
            return null;
        }
    }
    /**
     * Update workflow file
     */
    async updateWorkflow(fileName, config) {
        const workflowPath = path.join(this.workflowsDir, fileName);
        const yamlContent = yaml.dump(config, { lineWidth: -1, noRefs: true });
        fs.writeFileSync(workflowPath, yamlContent);
        this.emit('workflow:updated', { path: workflowPath });
    }
    /**
     * Delete workflow file
     */
    deleteWorkflow(fileName) {
        const workflowPath = path.join(this.workflowsDir, fileName);
        if (!fs.existsSync(workflowPath)) {
            return false;
        }
        fs.unlinkSync(workflowPath);
        this.emit('workflow:deleted', { path: workflowPath });
        return true;
    }
    /**
     * Validate workflow syntax
     */
    validateWorkflow(config) {
        const errors = [];
        // Check required fields
        if (!config.name) {
            errors.push('Workflow must have a name');
        }
        if (!config.on || Object.keys(config.on).length === 0) {
            errors.push('Workflow must have at least one trigger');
        }
        if (!config.jobs || Object.keys(config.jobs).length === 0) {
            errors.push('Workflow must have at least one job');
        }
        // Validate jobs
        for (const [jobId, job] of Object.entries(config.jobs || {})) {
            if (!job['runs-on']) {
                errors.push(`Job "${jobId}" must specify runs-on`);
            }
            if (!job.steps || job.steps.length === 0) {
                errors.push(`Job "${jobId}" must have at least one step`);
            }
            // Validate steps
            for (let i = 0; i < (job.steps || []).length; i++) {
                const step = job.steps[i];
                if (!step.uses && !step.run) {
                    errors.push(`Step ${i + 1} in job "${jobId}" must have either 'uses' or 'run'`);
                }
            }
            // Validate job dependencies
            if (job.needs) {
                const needs = Array.isArray(job.needs) ? job.needs : [job.needs];
                for (const dep of needs) {
                    if (!config.jobs[dep]) {
                        errors.push(`Job "${jobId}" depends on non-existent job "${dep}"`);
                    }
                }
            }
        }
        return {
            valid: errors.length === 0,
            errors,
        };
    }
    /**
     * Get workflow runs using GitHub CLI
     */
    async getWorkflowRuns(workflowName, limit = 10) {
        try {
            const args = ['run', 'list', '--json', 'databaseId,name,status,conclusion,createdAt,updatedAt,url,workflowDatabaseId,number,headBranch,headSha'];
            if (workflowName) {
                args.push('--workflow', workflowName);
            }
            args.push('--limit', String(limit));
            const output = await this.execGh(args);
            const runs = JSON.parse(output);
            return runs.map((run) => ({
                id: run.databaseId,
                name: run.name,
                status: run.status?.toLowerCase(),
                conclusion: run.conclusion?.toLowerCase(),
                created_at: run.createdAt,
                updated_at: run.updatedAt,
                html_url: run.url,
                workflow_id: run.workflowDatabaseId,
                run_number: run.number,
                head_branch: run.headBranch,
                head_sha: run.headSha,
            }));
        }
        catch {
            return [];
        }
    }
    /**
     * Trigger workflow manually
     */
    async triggerWorkflow(workflowName, ref = 'main', inputs) {
        try {
            const args = ['workflow', 'run', workflowName, '--ref', ref];
            if (inputs) {
                for (const [key, value] of Object.entries(inputs)) {
                    args.push('-f', `${key}=${value}`);
                }
            }
            await this.execGh(args);
            this.emit('workflow:triggered', { workflow: workflowName, ref, inputs });
            return true;
        }
        catch {
            return false;
        }
    }
    /**
     * View workflow run logs
     */
    async getRunLogs(runId) {
        try {
            const output = await this.execGh(['run', 'view', String(runId), '--log']);
            return output;
        }
        catch (error) {
            return error instanceof Error ? error.message : String(error);
        }
    }
    /**
     * Cancel workflow run
     */
    async cancelRun(runId) {
        try {
            await this.execGh(['run', 'cancel', String(runId)]);
            return true;
        }
        catch {
            return false;
        }
    }
    /**
     * Re-run workflow
     */
    async rerunWorkflow(runId, failedOnly = false) {
        try {
            const args = ['run', 'rerun', String(runId)];
            if (failedOnly) {
                args.push('--failed');
            }
            await this.execGh(args);
            return true;
        }
        catch {
            return false;
        }
    }
    /**
     * Analyze workflow for optimizations
     */
    analyzeWorkflow(config) {
        const suggestions = [];
        // Check for caching opportunities
        for (const [_jobId, job] of Object.entries(config.jobs || {})) {
            const hasSetupNode = job.steps?.some(s => s.uses?.includes('setup-node'));
            const hasCache = job.steps?.some(s => s.uses?.includes('actions/cache'));
            if (hasSetupNode && !hasCache) {
                const nodeStep = job.steps?.find(s => s.uses?.includes('setup-node'));
                if (!nodeStep?.with?.cache) {
                    suggestions.push({
                        type: 'caching',
                        message: 'Consider adding cache: "npm" to setup-node for faster builds',
                        severity: 'info',
                    });
                }
            }
        }
        // Check for parallel job opportunities
        const jobIds = Object.keys(config.jobs || {});
        if (jobIds.length === 1 && config.jobs) {
            const job = config.jobs[jobIds[0]];
            if (job.steps && job.steps.length > 10) {
                suggestions.push({
                    type: 'parallelization',
                    message: 'Consider splitting long job into multiple parallel jobs',
                    severity: 'info',
                });
            }
        }
        // Check for security issues
        for (const [jobId, job] of Object.entries(config.jobs || {})) {
            for (const step of job.steps || []) {
                // Check for unpinned actions
                if (step.uses && !step.uses.includes('@v') && !step.uses.includes('@sha')) {
                    suggestions.push({
                        type: 'security',
                        message: `Job "${jobId}": Action "${step.uses}" should be pinned to a specific version`,
                        severity: 'warning',
                    });
                }
                // Check for shell injection risks
                if (step.run && step.run.includes('${{')) {
                    suggestions.push({
                        type: 'security',
                        message: `Job "${jobId}": Direct use of expressions in run commands may be vulnerable to injection`,
                        severity: 'warning',
                    });
                }
            }
        }
        // Check for timeout
        for (const [jobId, job] of Object.entries(config.jobs || {})) {
            if (!job.timeout) {
                suggestions.push({
                    type: 'reliability',
                    message: `Job "${jobId}": Consider adding a timeout-minutes to prevent stuck workflows`,
                    severity: 'info',
                });
            }
        }
        return suggestions;
    }
    /**
     * Format workflow summary
     */
    formatSummary() {
        const workflows = this.listWorkflows();
        const lines = [
            '🔄 GitHub Actions Workflows',
            '═'.repeat(40),
            '',
        ];
        if (workflows.length === 0) {
            lines.push('No workflows found.');
            lines.push('');
            lines.push('Available templates:');
            for (const template of this.getTemplates()) {
                lines.push(`  • ${template}`);
            }
            lines.push('');
            lines.push('Use /actions create <template> to create a workflow');
        }
        else {
            lines.push(`Found ${workflows.length} workflow(s):`);
            lines.push('');
            for (const workflow of workflows) {
                const triggers = workflow.config?.on
                    ? Object.keys(workflow.config.on).join(', ')
                    : 'unknown';
                lines.push(`📄 ${workflow.name}`);
                lines.push(`   File: ${workflow.path}`);
                lines.push(`   Triggers: ${triggers}`);
                lines.push('');
            }
        }
        return lines.join('\n');
    }
    // ============================================================================
    // Private Methods
    // ============================================================================
    execGit(args) {
        return new Promise((resolve, reject) => {
            const proc = spawn('git', args, { stdio: ['ignore', 'pipe', 'pipe'] });
            let stdout = '';
            let stderr = '';
            proc.stdout.on('data', (data) => {
                stdout += data.toString();
            });
            proc.stderr.on('data', (data) => {
                stderr += data.toString();
            });
            proc.on('close', (code) => {
                if (code === 0) {
                    resolve(stdout.trim());
                }
                else {
                    reject(new Error(stderr || `Git exited with code ${code}`));
                }
            });
            proc.on('error', reject);
        });
    }
    execGh(args) {
        return new Promise((resolve, reject) => {
            const proc = spawn('gh', args, { stdio: ['ignore', 'pipe', 'pipe'] });
            let stdout = '';
            let stderr = '';
            proc.stdout.on('data', (data) => {
                stdout += data.toString();
            });
            proc.stderr.on('data', (data) => {
                stderr += data.toString();
            });
            proc.on('close', (code) => {
                if (code === 0) {
                    resolve(stdout.trim());
                }
                else {
                    reject(new Error(stderr || `gh exited with code ${code}`));
                }
            });
            proc.on('error', () => {
                reject(new Error('GitHub CLI (gh) not found. Install from https://cli.github.com/'));
            });
        });
    }
}
// ============================================================================
// Singleton
// ============================================================================
let managerInstance = null;
export function getGitHubActionsManager(config) {
    if (!managerInstance) {
        managerInstance = new GitHubActionsManager(config);
    }
    return managerInstance;
}
export function resetGitHubActionsManager() {
    managerInstance = null;
}
//# sourceMappingURL=github-actions.js.map