import { Worker, Job } from 'bullmq';
import { AccessibilityScanner } from '@wcag-ada/scanner';
import type { AccessibilityScanOptions } from '@wcag-ada/shared';
import { getWorkerConfig } from '@wcag-ada/config';
import { logger } from '../utils/logger';
import { prisma } from '../utils/prisma';
import { createRedisConnection } from '../utils/redis';

interface ScanJobData {
  jobId: string;
  websiteId: string;
  userId: string;
  options: AccessibilityScanOptions;
}

export class ScanWorker {
  private worker: Worker<ScanJobData> | null = null;
  private scanner: AccessibilityScanner | null = null;
  private config = getWorkerConfig();

  async start(): Promise<void> {
    // Initialize scanner
    this.scanner = new AccessibilityScanner(logger);
    await this.scanner.initialize();

    // Create worker
    this.worker = new Worker<ScanJobData>(
      this.config.queueName,
      async (job) => this.processJob(job),
      {
        connection: createRedisConnection(),
        concurrency: this.config.concurrency,
      }
    );

    // Setup event handlers
    this.worker.on('completed', (job) => {
      logger.info('Job completed', { jobId: job.id, data: job.data });
    });

    this.worker.on('failed', (job, err) => {
      logger.error('Job failed', { 
        jobId: job?.id, 
        error: err.message,
        stack: err.stack,
      });
    });

    this.worker.on('error', (err) => {
      logger.error('Worker error', err);
    });
  }

  private async processJob(job: Job<ScanJobData>): Promise<void> {
    const { jobId, websiteId, userId, options } = job.data;
    
    logger.info('Processing scan job', { jobId, websiteId });
    
    try {
      // Update job status
      await prisma.scanJob.update({
        where: { id: jobId },
        data: {
          status: 'RUNNING',
          startedAt: new Date(),
        },
      });
      
      // Perform scan
      if (!this.scanner) {
        throw new Error('Scanner not initialized');
      }
      
      const result = await this.scanner.scan(options);
      
      // Save result
      const scanResult = await prisma.scanResult.create({
        data: {
          websiteId,
          jobId,
          url: result.url,
          scanDuration: result.scanDuration,
          summary: result.summary as any,
          violations: result.violations as any,
          passes: result.passes as any,
          incomplete: result.incomplete as any,
          inapplicable: result.inapplicable as any,
          pageMetadata: result.pageMetadata as any,
          wcagCompliance: result.wcagCompliance as any,
        },
      });
      
      // Update job status
      await prisma.scanJob.update({
        where: { id: jobId },
        data: {
          status: 'COMPLETED',
          completedAt: new Date(),
        },
      });
      
      // Update website compliance score
      await prisma.website.update({
        where: { id: websiteId },
        data: {
          lastScanAt: new Date(),
          complianceScore: result.summary.score,
        },
      });
      
      logger.info('Scan job completed', {
        jobId,
        resultId: scanResult.id,
        score: result.summary.score,
      });
    } catch (error: any) {
      logger.error('Scan job failed', {
        jobId,
        error: error.message,
        stack: error.stack,
      });
      
      // Update job status
      await prisma.scanJob.update({
        where: { id: jobId },
        data: {
          status: 'FAILED',
          error: error.message,
          completedAt: new Date(),
        },
      });
      
      throw error;
    }
  }

  async stop(): Promise<void> {
    logger.info('Stopping scan worker...');
    
    if (this.worker) {
      await this.worker.close();
      this.worker = null;
    }
    
    if (this.scanner) {
      await this.scanner.close();
      this.scanner = null;
    }
    
    logger.info('Scan worker stopped');
  }
}