import cron from 'node-cron';
import { Queue } from 'bullmq';
import { getWorkerConfig } from '@wcag-ada/config';
import { logger } from '../utils/logger';
import { prisma } from '../utils/prisma';
import { createRedisConnection } from '../utils/redis';
import type { AccessibilityScanOptions } from '@wcag-ada/shared';

export class SchedulerService {
  private tasks: cron.ScheduledTask[] = [];
  private scanQueue: Queue | null = null;
  private config = getWorkerConfig();

  async start(): Promise<void> {
    // Create queue instance
    this.scanQueue = new Queue(this.config.queueName, {
      connection: createRedisConnection(),
    });

    // Schedule periodic check for websites that need scanning
    const task = cron.schedule('*/1 * * * *', async () => {
      await this.checkAndScheduleScans();
    }, {
      timezone: this.config.scheduler.timezone,
    });

    this.tasks.push(task);
    task.start();

    logger.info('Scheduler service started');
  }

  private async checkAndScheduleScans(): Promise<void> {
    try {
      const now = new Date();
      
      // Find websites that need scanning based on their schedule
      const websites = await prisma.website.findMany({
        where: {
          active: true,
          scanSchedule: {
            not: null,
          },
        },
      });

      for (const website of websites) {
        const schedule = website.scanSchedule as any;
        if (!schedule || schedule.frequency === 'manual') continue;

        const shouldScan = this.shouldScanWebsite(website, schedule, now);
        
        if (shouldScan) {
          await this.scheduleWebsiteScan(website);
        }
      }
    } catch (error) {
      logger.error('Error checking scheduled scans', error);
    }
  }

  private shouldScanWebsite(website: any, schedule: any, now: Date): boolean {
    if (!website.lastScanAt) return true;

    const lastScan = new Date(website.lastScanAt);
    const timeSinceLastScan = now.getTime() - lastScan.getTime();

    switch (schedule.frequency) {
      case 'hourly':
        return timeSinceLastScan >= 60 * 60 * 1000; // 1 hour
      case 'daily':
        return timeSinceLastScan >= 24 * 60 * 60 * 1000; // 24 hours
      case 'weekly':
        return timeSinceLastScan >= 7 * 24 * 60 * 60 * 1000; // 7 days
      case 'monthly':
        return timeSinceLastScan >= 30 * 24 * 60 * 60 * 1000; // 30 days
      default:
        return false;
    }
  }

  private async scheduleWebsiteScan(website: any): Promise<void> {
    try {
      // Create scan job in database
      const job = await prisma.scanJob.create({
        data: {
          websiteId: website.id,
          userId: website.userId,
          url: website.url,
          options: {
            url: website.url,
            ...(website.scanOptions as any),
            authenticate: website.authConfig as any,
          },
          status: 'PENDING',
        },
      });

      // Queue the scan
      if (this.scanQueue) {
        await this.scanQueue.add('scan', {
          jobId: job.id,
          websiteId: website.id,
          userId: website.userId,
          options: job.options as AccessibilityScanOptions,
        }, {
          jobId: job.id,
        });

        logger.info('Scheduled scan for website', {
          websiteId: website.id,
          jobId: job.id,
          url: website.url,
        });
      }
    } catch (error) {
      logger.error('Error scheduling website scan', {
        websiteId: website.id,
        error,
      });
    }
  }

  async stop(): Promise<void> {
    logger.info('Stopping scheduler service...');
    
    for (const task of this.tasks) {
      task.stop();
    }
    this.tasks = [];

    if (this.scanQueue) {
      await this.scanQueue.close();
      this.scanQueue = null;
    }

    logger.info('Scheduler service stopped');
  }
}