import { ComponentScanner } from '../scanners/ComponentScanner.js';
import Discovery from '../models/Discovery.js';
import sequelize from '../config/database.js';
import { QueryTypes } from 'sequelize';

/**
 * Background worker for processing discovery jobs.
 * Uses polling mechanism to pick up queued jobs.
 */
class DiscoveryWorker {
  constructor() {
    this.scanner = new ComponentScanner();
    this.isRunning = false;
    this.intervalId = null;
    this.POLL_INTERVAL = 5000; // 5 seconds
  }

  /**
   * Starts the polling loop.
   */
  startWorker() {
    if (this.isRunning) {
      console.log('[DiscoveryWorker] Worker already running');
      return;
    }

    console.log('[DiscoveryWorker] Starting worker...');
    this.isRunning = true;

    // Process immediately, then start interval
    this._processNextJob();
    this.intervalId = setInterval(() => this._processNextJob(), this.POLL_INTERVAL);

    // Handle graceful shutdown
    process.on('SIGTERM', () => this.stopWorker());
    process.on('SIGINT', () => this.stopWorker());
  }

  /**
   * Stops the polling loop gracefully.
   */
  stopWorker() {
    if (!this.isRunning) return;

    console.log('[DiscoveryWorker] Stopping worker...');
    this.isRunning = false;
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = null;
    }
  }

  /**
   * Processes a single job if available.
   * @private
   */
  async _processNextJob() {
    if (!this.isRunning) return;

    try {
      // Atomically claim a queued job (SQLite-compatible approach)
      const [affectedCount] = await sequelize.query(
        `UPDATE discoveries
         SET status = 'running', startedAt = datetime('now')
         WHERE id = (
           SELECT id FROM discoveries
           WHERE status = 'queued' AND type = 'component-audit'
           ORDER BY createdAt ASC
           LIMIT 1
         )`,
        { type: QueryTypes.UPDATE }
      );

      if (affectedCount === 0) return; // No jobs available

      // Fetch the claimed job
      const job = await Discovery.findOne({
        where: { status: 'running', type: 'component-audit' },
        order: [['startedAt', 'DESC']]
      });

      if (!job) return; // Race condition fallback

      console.log(`[DiscoveryWorker] Claimed job ${job.id} for project ${job.projectId}`);

      // Execute Scan
      try {
        const results = await this.scanner.scan(job.projectId);

        await job.update({
          status: 'completed',
          completedAt: new Date(),
          results: results,
          progress: 100
        });

        console.log(`[DiscoveryWorker] Job ${job.id} completed successfully - Created: ${results.created}, Updated: ${results.updated}, Matched: ${results.matched}`);

      } catch (scanError) {
        console.error(`[DiscoveryWorker] Job ${job.id} failed:`, scanError);

        await job.update({
          status: 'failed',
          completedAt: new Date(),
          error: scanError.message
        });
      }

    } catch (error) {
      console.error('[DiscoveryWorker] System error:', error);
    }
  }
}

// Singleton instance
const worker = new DiscoveryWorker();
export const startWorker = () => worker.startWorker();
export const stopWorker = () => worker.stopWorker();
