"use strict";
/**
 * Enhanced Background Jobs Generator
 * Generates comprehensive background job infrastructure
 *
 * Features:
 * - Job queue setup (Bull/BullMQ with Redis)
 * - Job processors and handlers
 * - Cron job scheduling
 * - Job retry logic
 * - Job progress tracking
 * - Job monitoring dashboard
 * - Dead letter queue
 * - Job priority and concurrency
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.enhancedBackgroundJobsGenerator = exports.EnhancedBackgroundJobsGenerator = void 0;
const path = __importStar(require("path"));
class EnhancedBackgroundJobsGenerator {
    id = 'enhanced-background-jobs';
    name = 'Enhanced Background Jobs Generator';
    description = 'Generates comprehensive background job infrastructure with queue management, scheduling, and monitoring';
    generate(context) {
        const { workflow, outputDirectory } = context;
        const files = [];
        if (!workflow.background_jobs) {
            return { files };
        }
        const backgroundJobs = workflow.background_jobs;
        // Generate job configuration
        files.push(this.generateJobConfig(backgroundJobs, outputDirectory));
        // Generate job queue
        files.push(this.generateJobQueue(backgroundJobs, outputDirectory));
        // Generate job definitions
        if (backgroundJobs.jobs && backgroundJobs.jobs.length > 0) {
            files.push(...this.generateJobHandlers(backgroundJobs, outputDirectory));
        }
        // Generate job processor/worker
        files.push(this.generateJobWorker(backgroundJobs, outputDirectory));
        // Generate cron jobs
        if (backgroundJobs.cron_jobs && backgroundJobs.cron_jobs.length > 0) {
            files.push(this.generateCronScheduler(backgroundJobs, outputDirectory));
        }
        // Generate job utilities
        files.push(this.generateJobUtilities(backgroundJobs, outputDirectory));
        // Generate monitoring dashboard
        if (backgroundJobs.dashboard?.enabled) {
            files.push(this.generateDashboard(backgroundJobs, outputDirectory));
        }
        // Generate dead letter queue handler
        if (backgroundJobs.dead_letter_queue?.enabled) {
            files.push(this.generateDeadLetterQueue(backgroundJobs, outputDirectory));
        }
        return { files };
    }
    generateJobConfig(backgroundJobs, outputDirectory) {
        const content = `/**
 * Background Jobs Configuration
 * Generated by Bangstack
 */

export const jobConfig = {
  provider: '${backgroundJobs.provider}',
  redis: {
    ${backgroundJobs.redis?.url ? `url: process.env.REDIS_URL || '${backgroundJobs.redis.url}',` : ''}
    ${backgroundJobs.redis?.host ? `host: process.env.REDIS_HOST || '${backgroundJobs.redis.host}',` : ''}
    ${backgroundJobs.redis?.port ? `port: parseInt(process.env.REDIS_PORT || '${backgroundJobs.redis.port}'),` : ''}
    ${backgroundJobs.redis?.password ? `password: process.env.REDIS_PASSWORD,` : ''}
  },
  queueConfig: {
    defaultConcurrency: ${backgroundJobs.queue_config?.default_concurrency || 5},
    removeOnComplete: ${backgroundJobs.queue_config?.remove_on_complete !== false ? (backgroundJobs.queue_config?.remove_on_complete || 100) : false},
    removeOnFail: ${backgroundJobs.queue_config?.remove_on_fail !== false ? (backgroundJobs.queue_config?.remove_on_fail || 1000) : false},
  },
  retry: {
    attempts: ${backgroundJobs.retry?.attempts || 3},
    backoff: {
      type: '${backgroundJobs.retry?.backoff?.type || 'exponential'}',
      delay: ${backgroundJobs.retry?.backoff?.delay || 1000},
    },
  },
  progressTracking: ${backgroundJobs.progress_tracking !== false},
  ${backgroundJobs.dashboard?.enabled ? `dashboard: {
    enabled: true,
    port: ${backgroundJobs.dashboard.port || 3001},
    ${backgroundJobs.dashboard.auth ? `auth: {
      username: process.env.DASHBOARD_USERNAME || '${backgroundJobs.dashboard.auth.username}',
      password: process.env.DASHBOARD_PASSWORD || '${backgroundJobs.dashboard.auth.password}',
    },` : ''}
  },` : ''}
  ${backgroundJobs.dead_letter_queue?.enabled ? `deadLetterQueue: {
    enabled: true,
    retention: '${backgroundJobs.dead_letter_queue.retention || '7d'}',
  },` : ''}
  ${backgroundJobs.priority_levels ? `priorityLevels: ${JSON.stringify(backgroundJobs.priority_levels)},` : ''}
};

export default jobConfig;
`;
        return {
            path: path.join(outputDirectory, 'api/src/config/jobs.ts'),
            content,
        };
    }
    generateJobQueue(backgroundJobs, outputDirectory) {
        const provider = backgroundJobs.provider;
        let content = '';
        if (provider === 'bullmq' || provider === 'bull') {
            content = `/**
 * Job Queue
 * Generated by Bangstack
 */

import { Queue } from '${provider}';
import { jobConfig } from '../config/jobs';

export const jobQueue = new Queue('jobs', {
  connection: jobConfig.redis,
  defaultJobOptions: {
    attempts: jobConfig.retry.attempts,
    backoff: {
      type: jobConfig.retry.backoff.type,
      delay: jobConfig.retry.backoff.delay,
    },
    removeOnComplete: jobConfig.queueConfig.removeOnComplete,
    removeOnFail: jobConfig.queueConfig.removeOnFail,
  },
});

/**
 * Add a job to the queue
 */
export async function addJob(
  name: string,
  data: any,
  options?: {
    priority?: number;
    delay?: number;
    attempts?: number;
  }
): Promise<void> {
  await jobQueue.add(name, data, options);
}

/**
 * Get job by ID
 */
export async function getJob(jobId: string): Promise<any> {
  return await jobQueue.getJob(jobId);
}

/**
 * Get job counts
 */
export async function getJobCounts(): Promise<any> {
  return await jobQueue.getJobCounts();
}

/**
 * Clean completed jobs
 */
export async function cleanCompletedJobs(grace: number = 3600000): Promise<void> {
  await jobQueue.clean(grace, 0, 'completed');
}

/**
 * Close queue
 */
export async function closeJobQueue(): Promise<void> {
  await jobQueue.close();
}
`;
        }
        return {
            path: path.join(outputDirectory, 'api/src/queues/job-queue.ts'),
            content,
        };
    }
    generateJobHandlers(backgroundJobs, outputDirectory) {
        const files = [];
        const jobs = backgroundJobs.jobs || [];
        jobs.forEach(job => {
            const content = `/**
 * ${job.name} Job Handler
 * Generated by Bangstack
 */

export interface ${job.name}Data {
  // Define job data interface
  [key: string]: any;
}

/**
 * Process ${job.name} job
 */
export async function process${job.name}(data: ${job.name}Data, updateProgress?: (progress: number) => Promise<void>): Promise<void> {
  console.log('Processing ${job.name}:', data);

  try {
    // TODO: Implement job logic here

    // Example progress tracking
    if (updateProgress) {
      await updateProgress(50);
    }

    // Complete job
    if (updateProgress) {
      await updateProgress(100);
    }

    console.log('${job.name} completed successfully');
  } catch (error) {
    console.error('${job.name} failed:', error);
    throw error;
  }
}
`;
            files.push({
                path: path.join(outputDirectory, `api/src/jobs/${job.name.toLowerCase()}-handler.ts`),
                content,
            });
        });
        return files;
    }
    generateJobWorker(backgroundJobs, outputDirectory) {
        const provider = backgroundJobs.provider;
        const jobs = backgroundJobs.jobs || [];
        const imports = jobs.map(job => `import { process${job.name} } from '../jobs/${job.name.toLowerCase()}-handler';`).join('\n');
        const handlers = jobs.map(job => `
  worker.process('${job.name}', ${job.concurrency || 'async'} (job) => {
    const updateProgress = jobConfig.progressTracking
      ? async (progress: number) => await job.updateProgress(progress)
      : undefined;

    return process${job.name}(job.data, updateProgress);
  });
`).join('\n');
        const content = `/**
 * Job Worker
 * Processes background jobs
 * Generated by Bangstack
 */

import { Worker } from '${provider}';
import { jobConfig } from '../config/jobs';
${imports}

export const worker = new Worker(
  'jobs',
  async (job) => {
    // Job processing is handled by individual processors
    console.log(\`Processing job: \${job.name}\`);
  },
  {
    connection: jobConfig.redis,
    concurrency: jobConfig.queueConfig.defaultConcurrency,
  }
);

${handlers}

// Event listeners
worker.on('completed', (job) => {
  console.log(\`Job completed: \${job.id}\`);
});

worker.on('failed', (job, error) => {
  console.error(\`Job failed: \${job?.id}\`, error);

  ${backgroundJobs.dead_letter_queue?.enabled ? `
  // Move to dead letter queue
  // TODO: Implement dead letter queue logic
  ` : ''}
});

worker.on('progress', (job, progress) => {
  console.log(\`Job progress: \${job.id} - \${progress}%\`);
});

worker.on('error', (error) => {
  console.error('Worker error:', error);
});

/**
 * Close worker
 */
export async function closeWorker(): Promise<void> {
  await worker.close();
}

/**
 * Graceful shutdown
 */
process.on('SIGTERM', async () => {
  console.log('Shutting down worker...');
  await closeWorker();
  process.exit(0);
});
`;
        return {
            path: path.join(outputDirectory, 'api/src/workers/job-worker.ts'),
            content,
        };
    }
    generateCronScheduler(backgroundJobs, outputDirectory) {
        const cronJobs = backgroundJobs.cron_jobs || [];
        const imports = cronJobs.map(job => `import { ${job.handler} } from '../jobs/${job.handler.toLowerCase()}';`).join('\n');
        const schedules = cronJobs.map(job => `
  // ${job.name}
  cron.schedule('${job.schedule}', async () => {
    console.log('Running cron job: ${job.name}');
    try {
      await ${job.handler}();
    } catch (error) {
      console.error('Cron job failed: ${job.name}', error);
    }
  }${job.timezone ? `, { timezone: '${job.timezone}' }` : ''});
`).join('\n');
        const content = `/**
 * Cron Job Scheduler
 * Generated by Bangstack
 */

import * as cron from 'node-cron';
${imports}

export function initializeCronJobs(): void {
  console.log('Initializing cron jobs...');

${schedules}

  console.log('Cron jobs initialized');
}

/**
 * Stop all cron jobs
 */
export function stopCronJobs(): void {
  console.log('Stopping cron jobs...');
  cron.getTasks().forEach(task => task.stop());
}
`;
        return {
            path: path.join(outputDirectory, 'api/src/jobs/cron-scheduler.ts'),
            content,
        };
    }
    generateJobUtilities(_backgroundJobs, outputDirectory) {
        const content = `/**
 * Job Utilities
 * Generated by Bangstack
 */

import { jobQueue } from '../queues/job-queue';

/**
 * Schedule a delayed job
 */
export async function scheduleJob(
  name: string,
  data: any,
  delayMs: number
): Promise<void> {
  await jobQueue.add(name, data, { delay: delayMs });
}

/**
 * Schedule a job to run at a specific time
 */
export async function scheduleJobAt(
  name: string,
  data: any,
  timestamp: Date
): Promise<void> {
  const delay = timestamp.getTime() - Date.now();
  if (delay < 0) {
    throw new Error('Cannot schedule job in the past');
  }
  await scheduleJob(name, data, delay);
}

/**
 * Cancel a job
 */
export async function cancelJob(jobId: string): Promise<void> {
  const job = await jobQueue.getJob(jobId);
  if (job) {
    await job.remove();
  }
}

/**
 * Retry a failed job
 */
export async function retryJob(jobId: string): Promise<void> {
  const job = await jobQueue.getJob(jobId);
  if (job) {
    await job.retry();
  }
}

/**
 * Get job status
 */
export async function getJobStatus(jobId: string): Promise<string | null> {
  const job = await jobQueue.getJob(jobId);
  if (!job) return null;

  const state = await job.getState();
  return state;
}

/**
 * Get queue statistics
 */
export async function getQueueStats(): Promise<{
  waiting: number;
  active: number;
  completed: number;
  failed: number;
  delayed: number;
}> {
  return await jobQueue.getJobCounts();
}
`;
        return {
            path: path.join(outputDirectory, 'api/src/utils/job-utils.ts'),
            content,
        };
    }
    generateDashboard(backgroundJobs, outputDirectory) {
        const content = `/**
 * Job Monitoring Dashboard
 * Generated by Bangstack
 */

import express from 'express';
import { createBullBoard } from '@bull-board/api';
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
import { ExpressAdapter } from '@bull-board/express';
import { jobQueue } from '../queues/job-queue';
import { jobConfig } from '../config/jobs';

const serverAdapter = new ExpressAdapter();
serverAdapter.setBasePath('/admin/queues');

createBullBoard({
  queues: [new BullMQAdapter(jobQueue)],
  serverAdapter: serverAdapter,
});

/**
 * Initialize dashboard
 */
export function initializeDashboard(app: express.Application): void {
  if (!jobConfig.dashboard?.enabled) {
    return;
  }

  ${backgroundJobs.dashboard?.auth ? `
  // Add basic authentication
  const basicAuth = (req: express.Request, res: express.Response, next: express.NextFunction) => {
    const auth = req.headers.authorization;

    if (!auth) {
      res.setHeader('WWW-Authenticate', 'Basic realm="Dashboard"');
      return res.status(401).send('Authentication required');
    }

    const [username, password] = Buffer.from(auth.split(' ')[1], 'base64')
      .toString()
      .split(':');

    if (
      username === jobConfig.dashboard.auth?.username &&
      password === jobConfig.dashboard.auth?.password
    ) {
      next();
    } else {
      res.status(401).send('Invalid credentials');
    }
  };

  app.use('/admin/queues', basicAuth, serverAdapter.getRouter());
  ` : `
  app.use('/admin/queues', serverAdapter.getRouter());
  `}

  console.log(\`Job dashboard available at: http://localhost:\${jobConfig.dashboard.port}/admin/queues\`);
}
`;
        return {
            path: path.join(outputDirectory, 'api/src/dashboard/job-dashboard.ts'),
            content,
        };
    }
    generateDeadLetterQueue(_backgroundJobs, outputDirectory) {
        const content = `/**
 * Dead Letter Queue Handler
 * Generated by Bangstack
 */

import { Queue, Worker } from 'bullmq';
import { jobConfig } from '../config/jobs';

export const deadLetterQueue = new Queue('dead-letter', {
  connection: jobConfig.redis,
});

/**
 * Move failed job to dead letter queue
 */
export async function moveToDeadLetterQueue(
  jobName: string,
  jobData: any,
  error: Error
): Promise<void> {
  await deadLetterQueue.add('failed-job', {
    originalJob: jobName,
    data: jobData,
    error: {
      message: error.message,
      stack: error.stack,
    },
    failedAt: new Date(),
  });
}

/**
 * Process dead letter queue (manual review)
 */
export const deadLetterWorker = new Worker(
  'dead-letter',
  async (job) => {
    console.log('Dead letter job:', job.data);
    // Manual processing or notification
  },
  {
    connection: jobConfig.redis,
  }
);

/**
 * Get failed jobs from dead letter queue
 */
export async function getFailedJobs(limit: number = 100): Promise<any[]> {
  const jobs = await deadLetterQueue.getJobs(['completed', 'failed', 'waiting'], 0, limit);
  return jobs;
}

/**
 * Retry job from dead letter queue
 */
export async function retryFromDeadLetter(jobId: string): Promise<void> {
  const job = await deadLetterQueue.getJob(jobId);
  if (job) {
    // TODO: Add original job back to main queue
    await job.remove();
  }
}
`;
        return {
            path: path.join(outputDirectory, 'api/src/queues/dead-letter-queue.ts'),
            content,
        };
    }
}
exports.EnhancedBackgroundJobsGenerator = EnhancedBackgroundJobsGenerator;
exports.enhancedBackgroundJobsGenerator = new EnhancedBackgroundJobsGenerator();
//# sourceMappingURL=enhanced-background-jobs-generator.js.map