import { Request, Response } from 'express';
import { logger, StructuredLogger } from '../utils/logger';
import { DocumentModel } from '../models/DocumentModel';
import { fileStorageService } from '../services/fileStorageService';
import { jobQueueService } from '../services/jobQueueService';
import { uploadProgressService } from '../services/uploadProgressService';
import { uploadMonitoringService } from '../services/uploadMonitoringService';

export const documentController = {
  async getUploadUrl(req: Request, res: Response): Promise<void> {
    console.log('🎯🎯🎯 GET UPLOAD URL ENDPOINT HIT!');
    console.log('🎯 Method:', req.method);
    console.log('🎯 URL:', req.url);
    console.log('🎯 Headers:', JSON.stringify(req.headers, null, 2));
    try {
      const userId = req.user?.uid;
      if (!userId) {
        res.status(401).json({ 
          error: 'User not authenticated',
          correlationId: req.correlationId 
        });
        return;
      }

      const { fileName, fileSize, contentType } = req.body;
      
      if (!fileName || !fileSize || !contentType) {
        res.status(400).json({
          error: 'Missing required fields: fileName, fileSize, contentType',
          correlationId: req.correlationId
        });
        return;
      }

      // Validate file type
      if (contentType !== 'application/pdf') {
        res.status(400).json({
          error: 'Only PDF files are supported',
          correlationId: req.correlationId
        });
        return;
      }

      // Validate file size (max 50MB)
      if (fileSize > 50 * 1024 * 1024) {
        res.status(400).json({
          error: 'File size exceeds 50MB limit',
          correlationId: req.correlationId
        });
        return;
      }

      // Generate unique file path
      const timestamp = Date.now();
      const sanitizedFileName = fileName.replace(/[^a-zA-Z0-9.-]/g, '_');
      const filePath = `uploads/${userId}/${timestamp}_${sanitizedFileName}`;

      // Create document record first
      const document = await DocumentModel.create({
        user_id: userId,
        original_file_name: fileName,
        file_path: filePath,
        file_size: fileSize,
        status: 'uploading'
      });

      // Generate signed upload URL
      const { fileStorageService } = await import('../services/fileStorageService');
      const uploadUrl = await fileStorageService.generateSignedUploadUrl(filePath, contentType);

      console.log('✅ Generated upload URL for document:', document.id);

      res.status(200).json({
        documentId: document.id,
        uploadUrl: uploadUrl,
        filePath: filePath,
        correlationId: req.correlationId || undefined
      });

    } catch (error) {
      console.log('❌ Get upload URL error:', error);
      logger.error('Get upload URL failed', { 
        error, 
        correlationId: req.correlationId 
      });
      
      res.status(500).json({ 
        error: 'Failed to generate upload URL',
        message: error instanceof Error ? error.message : 'Unknown error',
        correlationId: req.correlationId || undefined
      });
    }
  },

  async confirmUpload(req: Request, res: Response): Promise<void> {
    console.log('🔄 CONFIRM UPLOAD ENDPOINT CALLED');
    console.log('🔄 Request method:', req.method);
    console.log('🔄 Request path:', req.path);
    console.log('🔄 Request params:', req.params);
    console.log('🔄 Request body:', req.body);
    console.log('🔄 Request headers:', Object.keys(req.headers));
    
    try {
      const userId = req.user?.uid;
      if (!userId) {
        res.status(401).json({ 
          error: 'User not authenticated',
          correlationId: req.correlationId 
        });
        return;
      }

      const { id: documentId } = req.params;
      if (!documentId) {
        res.status(400).json({
          error: 'Document ID is required',
          correlationId: req.correlationId
        });
        return;
      }

      // Get document record
      const document = await DocumentModel.findById(documentId);
      if (!document) {
        res.status(404).json({
          error: 'Document not found',
          correlationId: req.correlationId
        });
        return;
      }

      // Verify user owns document
      if (document.user_id !== userId) {
        res.status(403).json({
          error: 'Access denied',
          correlationId: req.correlationId
        });
        return;
      }

      console.log('🔄 Starting Document AI processing for:', documentId);

      // Update status to processing
      await DocumentModel.updateById(documentId, { 
        status: 'processing_llm'
      });

      console.log('✅ Document status updated to processing_llm');

      // Acknowledge the request immediately and return the document
      res.status(202).json({
        message: 'Upload confirmed, processing has started.',
        document: document,
        status: 'processing'
      });

      console.log('✅ Response sent, starting background processing...');

      // Process in the background
      (async () => {
        try {
          console.log('Background processing started.');
          // Download file from Firebase Storage for Document AI processing
          const { fileStorageService } = await import('../services/fileStorageService');
          
          let fileBuffer: Buffer | null = null;
          let downloadError: string | null = null;
          for (let i = 0; i < 3; i++) {
            try {
              await new Promise(resolve => setTimeout(resolve, 2000 * (i + 1)));
              fileBuffer = await fileStorageService.getFile(document.file_path);
              if (fileBuffer) {
                console.log(`✅ File downloaded from storage on attempt ${i + 1}`);
                break;
              }
            } catch (err) {
              downloadError = err instanceof Error ? err.message : String(err);
              console.log(`❌ File download attempt ${i + 1} failed:`, downloadError);
            }
          }
          if (!fileBuffer) {
            const errMsg = downloadError || 'Failed to download uploaded file';
            console.log('Failed to download file from storage:', errMsg);
            await DocumentModel.updateById(documentId, { 
              status: 'failed',
              error_message: `Failed to download uploaded file: ${errMsg}`
            });
            return;
          }

          console.log('File downloaded, starting unified processor.');
          // Process with Unified Document Processor
          const { unifiedDocumentProcessor } = await import('../services/unifiedDocumentProcessor');
          
          const result = await unifiedDocumentProcessor.processDocument(
            documentId,
            userId,
            '', // Text is not needed for this strategy
            { 
              strategy: 'document_ai_genkit',
              fileBuffer: fileBuffer,
              fileName: document.original_file_name,
              mimeType: 'application/pdf'
            }
          );

          if (result.success) {
            console.log('✅ Processing successful.');
            // Update document with results
            await DocumentModel.updateById(documentId, { 
              status: 'completed',
              generated_summary: result.summary,
              analysis_data: result.analysisData,
              processing_completed_at: new Date()
            });

            console.log('✅ Document AI processing completed successfully for document:', documentId);
            console.log('✅ Summary length:', result.summary?.length || 0);
            console.log('✅ Processing time:', new Date().toISOString());

            // 🗑️ DELETE PDF after successful processing
            try {
              await fileStorageService.deleteFile(document.file_path);
              console.log('✅ PDF deleted after successful processing:', document.file_path);
            } catch (deleteError) {
              console.log('⚠️ Failed to delete PDF file:', deleteError);
              logger.warn('Failed to delete PDF after processing', { 
                filePath: document.file_path, 
                documentId, 
                error: deleteError 
              });
            }

            console.log('✅ Document AI processing completed successfully');
          } else {
            console.log('❌ Processing failed:', result.error);
            await DocumentModel.updateById(documentId, { 
              status: 'failed',
              error_message: result.error
            });

            console.log('❌ Document AI processing failed for document:', documentId);
            console.log('❌ Error:', result.error);

            // Also delete PDF on processing failure to avoid storage costs
            try {
              await fileStorageService.deleteFile(document.file_path);
              console.log('🗑️ PDF deleted after processing failure');
            } catch (deleteError) {
              console.log('⚠️ Failed to delete PDF file after error:', deleteError);
            }
          }
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Unknown error';
          const errorStack = error instanceof Error ? error.stack : undefined;
          const errorDetails = error instanceof Error ? {
            name: error.name,
            message: error.message,
            stack: error.stack
          } : {
            type: typeof error,
            value: error
          };
          
          console.log('❌ Background processing error:', errorMessage);
          console.log('❌ Error details:', errorDetails);
          console.log('❌ Error stack:', errorStack);
          
          logger.error('Background processing failed', { 
            error: errorMessage,
            errorDetails,
            documentId,
            stack: errorStack
          });
          await DocumentModel.updateById(documentId, { 
            status: 'failed',
            error_message: `Background processing failed: ${errorMessage}`
          });
        }
      })();

    } catch (error) {
      console.log('❌ Confirm upload error:', error);
      logger.error('Confirm upload failed', { 
        error, 
        correlationId: req.correlationId 
      });
      
      res.status(500).json({ 
        error: 'Upload confirmation failed',
        message: error instanceof Error ? error.message : 'Unknown error',
        correlationId: req.correlationId || undefined
      });
    }
  },

  async uploadDocument(req: Request, res: Response): Promise<void> {
    const startTime = Date.now();
    
    // 🔍 COMPREHENSIVE DEBUG: Log everything about the request
    console.log('🚀 =========================');
    console.log('🚀 DOCUMENT AI UPLOAD STARTED');
    console.log('🚀 Method:', req.method);
    console.log('🚀 URL:', req.url);
    console.log('🚀 Content-Type:', req.get('Content-Type'));
    console.log('🚀 Content-Length:', req.get('Content-Length'));
    console.log('🚀 Authorization header present:', !!req.get('Authorization'));
    console.log('🚀 User from token:', req.user?.uid || 'NOT_FOUND');
    
    // Debug body in detail
    console.log('🚀 Has body:', !!req.body);
    console.log('🚀 Body type:', typeof req.body);
    console.log('🚀 Body constructor:', req.body?.constructor?.name);
    console.log('🚀 Body length:', req.body?.length || 0);
    console.log('🚀 Is Buffer?:', Buffer.isBuffer(req.body));
    
    // Debug all headers
    console.log('🚀 All headers:', JSON.stringify(req.headers, null, 2));
    
    // Debug request properties
    console.log('🚀 Request readable:', req.readable);
    console.log('🚀 Request complete:', req.complete);
    
    // If body exists, show first few bytes
    if (req.body && req.body.length > 0) {
      const preview = req.body.slice(0, 100).toString('hex');
      console.log('🚀 Body preview (hex):', preview);
      
      // Try to see if it contains multipart boundary
      const bodyStr = req.body.toString('utf8', 0, Math.min(500, req.body.length));
      console.log('🚀 Body preview (string):', bodyStr.substring(0, 200));
    }
    
    console.log('🚀 =========================');
    
    try {
      const userId = req.user?.uid;
      if (!userId) {
        console.log('❌ Authentication failed - no userId');
        res.status(401).json({ 
          error: 'User not authenticated',
          correlationId: req.correlationId 
        });
        return;
      }
      
      console.log('✅ Authentication successful for user:', userId);

      // Get raw body buffer for Document AI processing
      const rawBody = req.body;
      if (!rawBody || rawBody.length === 0) {
        res.status(400).json({ 
          error: 'No file data received',
          correlationId: req.correlationId,
          debug: {
            method: req.method,
            contentType: req.get('Content-Type'),
            contentLength: req.get('Content-Length'),
            hasRawBody: !!rawBody,
            rawBodySize: rawBody?.length || 0,
            bodyType: typeof rawBody
          }
        });
        return;
      }

      console.log('✅ Found raw body buffer:', rawBody.length, 'bytes');
      
      // Create document record first
      const document = await DocumentModel.create({
        user_id: userId,
        original_file_name: 'uploaded-document.pdf',
        file_path: '',
        file_size: rawBody.length,
        status: 'processing_llm'
      });

      console.log('✅ Document record created:', document.id);

      // Process with Document AI directly
      const { DocumentAiGenkitProcessor } = await import('../services/documentAiGenkitProcessor');
      const processor = new DocumentAiGenkitProcessor();
      
      console.log('✅ Starting Document AI processing...');
      const result = await processor.processDocument(
        document.id,
        userId,
        rawBody,
        'uploaded-document.pdf',
        'application/pdf'
      );

      if (result.success) {
        await DocumentModel.updateById(document.id, { 
          status: 'completed',
          generated_summary: result.content,
          processing_completed_at: new Date()
        });

        console.log('✅ Document AI processing completed successfully');

        res.status(201).json({
          id: document.id,
          name: 'uploaded-document.pdf',
          originalName: 'uploaded-document.pdf',
          status: 'completed',
          uploadedAt: document.created_at,
          uploadedBy: userId,
          fileSize: rawBody.length,
          summary: result.content,
          correlationId: req.correlationId || undefined
        });
        return;
      } else {
        console.log('❌ Document AI processing failed:', result.error);
        await DocumentModel.updateById(document.id, { 
          status: 'failed',
          error_message: result.error
        });

        res.status(500).json({
          error: 'Document processing failed',
          message: result.error,
          correlationId: req.correlationId || undefined
        });
        return;
      }

    } catch (error) {
      console.log('❌ Upload error:', error);
      
      logger.error('Upload document failed', { 
        error, 
        correlationId: req.correlationId 
      });
      
      res.status(500).json({ 
        error: 'Upload failed',
        message: error instanceof Error ? error.message : 'Unknown error',
        correlationId: req.correlationId || undefined
      });
    }
  },

  async getDocuments(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.user?.uid;
      if (!userId) {
        res.status(401).json({ 
          error: 'User not authenticated',
          correlationId: req.correlationId 
        });
        return;
      }

      const documents = await DocumentModel.findByUserId(userId);
      
      const formattedDocuments = documents.map(doc => ({
        id: doc.id,
        name: doc.original_file_name,
        originalName: doc.original_file_name,
        status: doc.status,
        uploadedAt: doc.created_at,
        processedAt: doc.processing_completed_at,
        uploadedBy: userId,
        fileSize: doc.file_size,
        summary: doc.generated_summary,
        error: doc.error_message,
        extractedData: doc.analysis_data || (doc.extracted_text ? { text: doc.extracted_text } : undefined)
      }));

      res.json({
        documents: formattedDocuments,
        correlationId: req.correlationId || undefined
      });
    } catch (error) {
      logger.error('Get documents failed', { 
        error, 
        correlationId: req.correlationId 
      });
      res.status(500).json({ 
        error: 'Get documents failed',
        correlationId: req.correlationId || undefined
      });
    }
  },

  async getDocument(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.user?.uid;
      if (!userId) {
        res.status(401).json({ 
          error: 'User not authenticated',
          correlationId: req.correlationId 
        });
        return;
      }

      const { id } = req.params;
      if (!id) {
        res.status(400).json({ 
          error: 'Document ID is required',
          correlationId: req.correlationId 
        });
        return;
      }

      const document = await DocumentModel.findById(id);
      
      if (!document) {
        res.status(404).json({ 
          error: 'Document not found',
          correlationId: req.correlationId 
        });
        return;
      }

      // Check if user owns the document
      if (document.user_id !== userId) {
        res.status(403).json({ 
          error: 'Access denied',
          correlationId: req.correlationId 
        });
        return;
      }

      const formattedDocument = {
        id: document.id,
        name: document.original_file_name,
        originalName: document.original_file_name,
        status: document.status,
        uploadedAt: document.created_at,
        processedAt: document.updated_at,
        uploadedBy: userId,
        fileSize: document.file_size,
        summary: document.generated_summary,
        error: document.error_message,
        extractedData: document.analysis_data || (document.extracted_text ? { text: document.extracted_text } : undefined)
      };

      res.json({
        ...formattedDocument,
        correlationId: req.correlationId || undefined
      });
    } catch (error) {
      logger.error('Get document failed', { 
        error, 
        correlationId: req.correlationId 
      });
      res.status(500).json({ 
        error: 'Get document failed',
        correlationId: req.correlationId || undefined
      });
    }
  },

  async getDocumentProgress(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.user?.uid;
      if (!userId) {
        res.status(401).json({ 
          error: 'User not authenticated',
          correlationId: req.correlationId 
        });
        return;
      }

      const { id } = req.params;
      if (!id) {
        res.status(400).json({ 
          error: 'Document ID is required',
          correlationId: req.correlationId 
        });
        return;
      }

      const document = await DocumentModel.findById(id);
      
      if (!document) {
        res.status(404).json({ 
          error: 'Document not found',
          correlationId: req.correlationId 
        });
        return;
      }

      // Check if user owns the document
      if (document.user_id !== userId) {
        res.status(403).json({ 
          error: 'Access denied',
          correlationId: req.correlationId 
        });
        return;
      }

      // Get progress from upload progress service
      const progress = uploadProgressService.getProgress(id);
      
      // If no progress data from service, calculate based on document status
      let calculatedProgress = 0;
      if (document.status === 'completed') {
        calculatedProgress = 100;
      } else if (document.status === 'processing_llm' || document.status === 'generating_pdf') {
        calculatedProgress = 75;
      } else if (document.status === 'extracting_text') {
        calculatedProgress = 25;
      } else if (document.status === 'uploaded') {
        calculatedProgress = 10;
      }
      
      res.json({
        id: document.id,
        status: document.status,
        progress: progress ? progress.progress : calculatedProgress,
        uploadedAt: document.created_at,
        processedAt: document.processing_completed_at,
        correlationId: req.correlationId || undefined
      });
    } catch (error) {
      logger.error('Get document progress failed', { 
        error, 
        correlationId: req.correlationId 
      });
      res.status(500).json({ 
        error: 'Get document progress failed',
        correlationId: req.correlationId || undefined
      });
    }
  },

  async deleteDocument(req: Request, res: Response): Promise<void> {
    try {
      const userId = req.user?.uid;
      if (!userId) {
        res.status(401).json({ 
          error: 'User not authenticated',
          correlationId: req.correlationId 
        });
        return;
      }

      const { id } = req.params;
      if (!id) {
        res.status(400).json({ 
          error: 'Document ID is required',
          correlationId: req.correlationId 
        });
        return;
      }

      const document = await DocumentModel.findById(id);
      
      if (!document) {
        res.status(404).json({ 
          error: 'Document not found',
          correlationId: req.correlationId 
        });
        return;
      }

      // Check if user owns the document
      if (document.user_id !== userId) {
        res.status(403).json({ 
          error: 'Access denied',
          correlationId: req.correlationId 
        });
        return;
      }

      // Delete from database
      const deleted = await DocumentModel.delete(id);
      
      if (!deleted) {
        res.status(500).json({ 
          error: 'Failed to delete document',
          correlationId: req.correlationId 
        });
        return;
      }

      // Delete file from storage
      try {
        await fileStorageService.deleteFile(document.file_path);
      } catch (error) {
        logger.warn('Failed to delete file from storage', { 
          error, 
          filePath: document.file_path,
          correlationId: req.correlationId 
        });
      }

      res.json({ 
        message: 'Document deleted successfully',
        correlationId: req.correlationId || undefined
      });
    } catch (error) {
      logger.error('Delete document failed', { 
        error, 
        correlationId: req.correlationId 
      });
      res.status(500).json({ 
        error: 'Delete document failed',
        correlationId: req.correlationId || undefined
      });
    }
  },

  async getDocumentText(documentId: string): Promise<string> {
    try {
      // Get document from database
      const document = await DocumentModel.findById(documentId);
      if (!document) {
        throw new Error('Document not found');
      }

      // Read file from storage
      const filePath = document.file_path;
      
      // Check if file exists
      try {
        const fileBuffer = await fileStorageService.getFile(filePath);
        if (!fileBuffer) {
          throw new Error('Document file not accessible');
        }

        // For PDF files, extract text using pdf-parse
        if (filePath.toLowerCase().endsWith('.pdf')) {
          logger.info('Extracting text from PDF file', { documentId, filePath });
          
          try {
            const pdfParse = require('pdf-parse');
            const data = await pdfParse(fileBuffer);
            
            const extractedText = data.text;
            
            logger.info('PDF text extraction completed', {
              documentId,
              textLength: extractedText.length,
              pages: data.numpages,
              fileSize: fileBuffer.length
            });

            // Update document with extracted text
            await DocumentModel.updateById(documentId, {
              extracted_text: extractedText
            });

            return extractedText;
          } catch (pdfError) {
            logger.error('PDF text extraction failed', { documentId, error: pdfError });
            
            // Return a minimal error message instead of hardcoded text
            throw new Error(`PDF text extraction failed: ${pdfError instanceof Error ? pdfError.message : 'Unknown error'}`);
          }
        } else {
          // For text files, read the content directly
          const fileContent = fileBuffer.toString('utf-8');
          return fileContent;
        }
        
      } catch (fileError) {
        logger.error('Document file not accessible', { filePath, documentId, error: fileError });
        throw new Error('Document file not accessible');
      }
      
    } catch (error) {
      logger.error('Get document text failed', { error, documentId });
      throw new Error('Failed to get document text');
    }
  }
};