import { Router } from 'express';
import { addCrawlJob, crawlerQueue } from '../queues/crawlerQueue';
import { CrawlerConfig } from '../types/crawler';
import { logger } from '@cloneweb/shared';

export const crawlerRoutes = Router();

// Start a new crawl job
crawlerRoutes.post('/crawl', async (req, res) => {
  try {
    const { projectId, startUrl, config } = req.body;
    
    // Validate required fields
    if (!projectId || !startUrl) {
      return res.status(400).json({
        error: 'Missing required fields: projectId, startUrl'
      });
    }
    
    // Default crawler configuration
    const defaultConfig: CrawlerConfig = {
      maxDepth: 3,
      maxPages: 100,
      respectRobots: true,
      rateLimit: 2, // requests per second
      userAgent: 'CloneWeb-Bot/1.0',
      timeout: 30000,
      viewport: {
        width: 1920,
        height: 1080
      },
      waitForTimeout: 2000
    };
    
    const crawlerConfig: CrawlerConfig = {
      ...defaultConfig,
      ...config
    };
    
    // Add job to queue
    const job = await addCrawlJob(projectId, startUrl, crawlerConfig);
    
    logger.info(`Created crawl job ${job.id} for project ${projectId}`);
    
    res.json({
      jobId: job.id,
      projectId,
      startUrl,
      config: crawlerConfig,
      status: 'queued'
    });
    
  } catch (error) {
    logger.error('Failed to create crawl job:', error);
    res.status(500).json({
      error: 'Failed to create crawl job',
      message: error instanceof Error ? error.message : 'Unknown error'
    });
  }
});

// Get job status
crawlerRoutes.get('/job/:jobId', async (req, res) => {
  try {
    const { jobId } = req.params;
    const job = await crawlerQueue.getJob(jobId);
    
    if (!job) {
      return res.status(404).json({
        error: 'Job not found'
      });
    }
    
    const state = await job.getState();
    const progress = job.progress();
    
    res.json({
      jobId: job.id,
      state,
      progress,
      data: job.data,
      result: job.returnvalue,
      failedReason: job.failedReason,
      createdAt: new Date(job.timestamp),
      processedAt: job.processedOn ? new Date(job.processedOn) : null,
      finishedAt: job.finishedOn ? new Date(job.finishedOn) : null
    });
    
  } catch (error) {
    logger.error('Failed to get job status:', error);
    res.status(500).json({
      error: 'Failed to get job status',
      message: error instanceof Error ? error.message : 'Unknown error'
    });
  }
});

// Get all jobs for a project
crawlerRoutes.get('/project/:projectId/jobs', async (req, res) => {
  try {
    const { projectId } = req.params;
    const { status, limit = 10, offset = 0 } = req.query;
    
    // Get jobs from queue
    let jobs;
    if (status === 'waiting') {
      jobs = await crawlerQueue.getWaiting(Number(offset), Number(offset) + Number(limit) - 1);
    } else if (status === 'active') {
      jobs = await crawlerQueue.getActive(Number(offset), Number(offset) + Number(limit) - 1);
    } else if (status === 'completed') {
      jobs = await crawlerQueue.getCompleted(Number(offset), Number(offset) + Number(limit) - 1);
    } else if (status === 'failed') {
      jobs = await crawlerQueue.getFailed(Number(offset), Number(offset) + Number(limit) - 1);
    } else {
      // Get all jobs
      const [waiting, active, completed, failed] = await Promise.all([
        crawlerQueue.getWaiting(0, Number(limit) - 1),
        crawlerQueue.getActive(0, Number(limit) - 1),
        crawlerQueue.getCompleted(0, Number(limit) - 1),
        crawlerQueue.getFailed(0, Number(limit) - 1)
      ]);
      jobs = [...waiting, ...active, ...completed, ...failed];
    }
    
    // Filter by project ID
    const projectJobs = jobs.filter(job => job.data.projectId === projectId);
    
    const jobsWithStatus = await Promise.all(
      projectJobs.map(async (job) => ({
        jobId: job.id,
        state: await job.getState(),
        progress: job.progress(),
        data: job.data,
        createdAt: new Date(job.timestamp),
        processedAt: job.processedOn ? new Date(job.processedOn) : null,
        finishedAt: job.finishedOn ? new Date(job.finishedOn) : null
      }))
    );
    
    res.json({
      jobs: jobsWithStatus,
      total: projectJobs.length,
      limit: Number(limit),
      offset: Number(offset)
    });
    
  } catch (error) {
    logger.error('Failed to get project jobs:', error);
    res.status(500).json({
      error: 'Failed to get project jobs',
      message: error instanceof Error ? error.message : 'Unknown error'
    });
  }
});

// Cancel a job
crawlerRoutes.delete('/job/:jobId', async (req, res) => {
  try {
    const { jobId } = req.params;
    const job = await crawlerQueue.getJob(jobId);
    
    if (!job) {
      return res.status(404).json({
        error: 'Job not found'
      });
    }
    
    await job.remove();
    
    logger.info(`Cancelled crawl job ${jobId}`);
    
    res.json({
      message: 'Job cancelled successfully',
      jobId
    });
    
  } catch (error) {
    logger.error('Failed to cancel job:', error);
    res.status(500).json({
      error: 'Failed to cancel job',
      message: error instanceof Error ? error.message : 'Unknown error'
    });
  }
});

// Get queue statistics
crawlerRoutes.get('/stats', async (req, res) => {
  try {
    const [waiting, active, completed, failed] = await Promise.all([
      crawlerQueue.getWaiting(),
      crawlerQueue.getActive(),
      crawlerQueue.getCompleted(),
      crawlerQueue.getFailed()
    ]);
    
    res.json({
      waiting: waiting.length,
      active: active.length,
      completed: completed.length,
      failed: failed.length,
      total: waiting.length + active.length + completed.length + failed.length
    });
    
  } catch (error) {
    logger.error('Failed to get queue stats:', error);
    res.status(500).json({
      error: 'Failed to get queue stats',
      message: error instanceof Error ? error.message : 'Unknown error'
    });
  }
});