/**
 * Bulk Processing Routes for Redirect Intelligence v2
 * 
 * Handles CSV upload, bulk job creation, and progress tracking
 */

import express from 'express';
import multer from 'multer';
import path from 'path';
import fs from 'fs/promises';
import { z } from 'zod';
import { requireAuth } from '../middleware/auth.middleware';
import { bulkRateLimit, addRateLimitStatus } from '../middleware/rate-limit.middleware';
import { BulkProcessorService } from '../services/bulk-processor.service';
import { logger } from '../lib/logger';

const router = express.Router();
const bulkProcessor = new BulkProcessorService();

// Configure multer for file uploads
const upload = multer({
  dest: 'uploads/',
  limits: {
    fileSize: 5 * 1024 * 1024, // 5MB max file size
    files: 1,
  },
  fileFilter: (req, file, cb) => {
    // Only allow CSV files
    if (file.mimetype === 'text/csv' || file.originalname.toLowerCase().endsWith('.csv')) {
      cb(null, true);
    } else {
      cb(new Error('Only CSV files are allowed'));
    }
  },
});

// Validation schemas
const CreateBulkJobSchema = z.object({
  projectId: z.string().optional(),
  urls: z.array(z.object({
    url: z.string().url(),
    label: z.string().optional(),
    metadata: z.record(z.any()).optional(),
  })).min(1).max(1000),
  options: z.object({
    method: z.enum(['GET', 'POST', 'HEAD']).default('GET'),
    userAgent: z.string().optional(),
    maxHops: z.number().min(1).max(20).default(10),
    timeout: z.number().min(1000).max(30000).default(15000),
    enableSSLAnalysis: z.boolean().default(true),
    enableSEOAnalysis: z.boolean().default(true),
    enableSecurityAnalysis: z.boolean().default(true),
    headers: z.record(z.string()).optional(),
  }).default({}),
});

const BulkJobParamsSchema = z.object({
  jobId: z.string().min(1),
});

const GetJobsQuerySchema = z.object({
  limit: z.string().transform(val => parseInt(val) || 20).refine(val => val > 0 && val <= 100),
  offset: z.string().transform(val => parseInt(val) || 0).refine(val => val >= 0),
}).partial();

/**
 * POST /api/v2/bulk/upload
 * Upload CSV file and create bulk tracking job
 */
router.post('/upload', requireAuth, bulkRateLimit, upload.single('file'), async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({
        success: false,
        error: 'No file uploaded',
      });
    }

    const userId = req.user!.id;
    const organizationId = req.user!.memberships?.[0]?.organizationId;

    // Parse options from request body
    const options = req.body.options ? JSON.parse(req.body.options) : {};

    logger.info(`Processing CSV upload for user: ${userId}`, {
      filename: req.file.originalname,
      size: req.file.size,
    });

    // Create bulk job from CSV
    const job = await bulkProcessor.createBulkJobFromCsv(
      userId,
      organizationId,
      req.file.path,
      options
    );

    res.json({
      success: true,
      data: {
        jobId: job.id,
        status: job.status,
        progress: job.progress,
        estimatedCompletionAt: job.estimatedCompletionAt,
      },
    });

  } catch (error) {
    logger.error('CSV upload failed:', error);
    
    // Clean up uploaded file on error
    if (req.file) {
      await fs.unlink(req.file.path).catch(() => {});
    }

    res.status(500).json({
      success: false,
      error: error instanceof Error ? error.message : 'Failed to process CSV upload',
    });
  }
});

/**
 * POST /api/v2/bulk/jobs
 * Create bulk tracking job with URL array
 */
router.post('/jobs', requireAuth, bulkRateLimit, async (req, res) => {
  try {
    const userId = req.user!.id;
    const organizationId = req.user!.memberships?.[0]?.organizationId;

    // Validate request body
    const validatedData = CreateBulkJobSchema.parse(req.body);

    logger.info(`Creating bulk job for user: ${userId}`, {
      urlCount: validatedData.urls.length,
      projectId: validatedData.projectId,
    });

    // Create bulk job
    const job = await bulkProcessor.createBulkJob(userId, organizationId, validatedData);

    res.status(201).json({
      success: true,
      data: {
        jobId: job.id,
        status: job.status,
        progress: job.progress,
        estimatedCompletionAt: job.estimatedCompletionAt,
        urls: job.urls.length, // Don't return the full URL list for privacy
      },
    });

  } catch (error) {
    logger.error('Bulk job creation failed:', error);

    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Validation failed',
        details: error.errors,
      });
    }

    res.status(500).json({
      success: false,
      error: error instanceof Error ? error.message : 'Failed to create bulk job',
    });
  }
});

/**
 * GET /api/v2/bulk/jobs
 * Get user's bulk jobs with pagination
 */
router.get('/jobs', requireAuth, addRateLimitStatus('bulk'), async (req, res) => {
  try {
    const userId = req.user!.id;
    const query = GetJobsQuerySchema.parse(req.query);

    const jobs = await bulkProcessor.getUserBulkJobs(
      userId,
      query.limit || 20,
      query.offset || 0
    );

    // Remove sensitive data from response
    const sanitizedJobs = jobs.map(job => ({
      id: job.id,
      status: job.status,
      progress: job.progress,
      createdAt: job.createdAt,
      startedAt: job.startedAt,
      finishedAt: job.finishedAt,
      estimatedCompletionAt: job.estimatedCompletionAt,
      projectId: job.projectId,
      urlCount: job.urls.length,
      options: job.options,
    }));

    res.json({
      success: true,
      data: sanitizedJobs,
      meta: {
        limit: query.limit || 20,
        offset: query.offset || 0,
        total: sanitizedJobs.length,
      },
    });

  } catch (error) {
    logger.error('Failed to get bulk jobs:', error);

    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Invalid query parameters',
        details: error.errors,
      });
    }

    res.status(500).json({
      success: false,
      error: 'Failed to retrieve bulk jobs',
    });
  }
});

/**
 * GET /api/v2/bulk/jobs/:jobId
 * Get specific bulk job details and progress
 */
router.get('/jobs/:jobId', requireAuth, async (req, res) => {
  try {
    const userId = req.user!.id;
    const { jobId } = BulkJobParamsSchema.parse(req.params);

    const job = await bulkProcessor.getBulkJob(jobId, userId);

    if (!job) {
      return res.status(404).json({
        success: false,
        error: 'Bulk job not found',
      });
    }

    // Include results only if job is completed
    const responseData: any = {
      id: job.id,
      status: job.status,
      progress: job.progress,
      createdAt: job.createdAt,
      startedAt: job.startedAt,
      finishedAt: job.finishedAt,
      estimatedCompletionAt: job.estimatedCompletionAt,
      projectId: job.projectId,
      urlCount: job.urls.length,
      options: job.options,
    };

    // Include results if job is completed
    if (job.status === 'completed' && job.results) {
      responseData.results = job.results;
    }

    res.json({
      success: true,
      data: responseData,
    });

  } catch (error) {
    logger.error('Failed to get bulk job:', error);

    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Invalid job ID',
        details: error.errors,
      });
    }

    res.status(500).json({
      success: false,
      error: 'Failed to retrieve bulk job',
    });
  }
});

/**
 * DELETE /api/v2/bulk/jobs/:jobId
 * Cancel a bulk job
 */
router.delete('/jobs/:jobId', requireAuth, async (req, res) => {
  try {
    const userId = req.user!.id;
    const { jobId } = BulkJobParamsSchema.parse(req.params);

    const success = await bulkProcessor.cancelBulkJob(jobId, userId);

    if (!success) {
      return res.status(404).json({
        success: false,
        error: 'Bulk job not found or cannot be cancelled',
      });
    }

    res.json({
      success: true,
      message: 'Bulk job cancelled successfully',
    });

  } catch (error) {
    logger.error('Failed to cancel bulk job:', error);

    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Invalid job ID',
        details: error.errors,
      });
    }

    res.status(500).json({
      success: false,
      error: 'Failed to cancel bulk job',
    });
  }
});

/**
 * GET /api/v2/bulk/jobs/:jobId/export/csv
 * Export bulk job results as CSV
 */
router.get('/jobs/:jobId/export/csv', requireAuth, async (req, res) => {
  try {
    const userId = req.user!.id;
    const { jobId } = BulkJobParamsSchema.parse(req.params);

    const filePath = await bulkProcessor.exportResultsToCsv(jobId, userId);

    // Set headers for file download
    res.setHeader('Content-Type', 'text/csv');
    res.setHeader('Content-Disposition', `attachment; filename="bulk-results-${jobId}.csv"`);

    // Stream file and clean up after
    const fileStream = require('fs').createReadStream(filePath);
    fileStream.pipe(res);

    fileStream.on('end', async () => {
      // Clean up file after download
      await fs.unlink(filePath).catch(() => {});
    });

    fileStream.on('error', (error: Error) => {
      logger.error('File streaming error:', error);
      res.status(500).json({
        success: false,
        error: 'Failed to stream results file',
      });
    });

  } catch (error) {
    logger.error('Failed to export bulk job results:', error);

    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Invalid job ID',
        details: error.errors,
      });
    }

    res.status(500).json({
      success: false,
      error: error instanceof Error ? error.message : 'Failed to export results',
    });
  }
});

/**
 * GET /api/v2/bulk/stats
 * Get queue statistics
 */
router.get('/stats', requireAuth, async (req, res) => {
  try {
    const stats = await bulkProcessor.getQueueStats();

    res.json({
      success: true,
      data: {
        queue: stats,
        timestamp: new Date().toISOString(),
      },
    });

  } catch (error) {
    logger.error('Failed to get queue stats:', error);
    res.status(500).json({
      success: false,
      error: 'Failed to retrieve queue statistics',
    });
  }
});

/**
 * DELETE /api/v2/bulk/cleanup
 * Clean up old bulk jobs and files (admin only)
 */
router.delete('/cleanup', requireAuth, async (req, res) => {
  try {
    // Only allow admin users to run cleanup
    const user = req.user!;
    const isAdmin = user.memberships?.some(m => m.role === 'ADMIN' || m.role === 'OWNER');
    
    if (!isAdmin) {
      return res.status(403).json({
        success: false,
        error: 'Admin privileges required',
      });
    }

    const maxAgeHours = parseInt(req.query.maxAge as string) || 72; // Default 3 days
    await bulkProcessor.cleanupOldJobs(maxAgeHours);

    res.json({
      success: true,
      message: `Cleanup completed for jobs older than ${maxAgeHours} hours`,
    });

  } catch (error) {
    logger.error('Failed to cleanup old jobs:', error);
    res.status(500).json({
      success: false,
      error: 'Failed to cleanup old jobs',
    });
  }
});

export default router;