const express = require('express');
const multer = require('multer');
const axios = require('axios');
const bodyParser = require('body-parser');
const cors = require('cors');
const session = require('express-session');
const { v4: uuidv4 } = require('uuid');
const fs = require('fs-extra');
const path = require('path');
const bcrypt = require('bcrypt');
const flash = require('connect-flash');
require('dotenv').config();

// Document processing utilities
const crypto = require('crypto');

// Document chunking configuration
const CHUNK_SIZE = 20000; // Larger chunks for FormData uploads (20KB)
const CHUNK_OVERLAP = 200; // Overlap between chunks
const MAX_DOCUMENT_SIZE = 1000000; // 1MB limit for document content

// Flowise document store configuration
const FLOWISE_BASE_URL = 'https://flowise.suika.cc';
const FLOWISE_DOCUMENT_STORE_ID = 'e293dc23-7cb2-4522-a057-4f0c4b0a444c';
const FLOWISE_API_KEY = process.env.FLOWISE_API_KEY || null;

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static('public'));
app.use(session({
  secret: process.env.SESSION_SECRET || 'educat-secret-key',
  resave: false,
  saveUninitialized: false,
  cookie: { secure: false, maxAge: 24 * 60 * 60 * 1000 } // 24 hours
}));
app.use(flash());

// Set EJS as view engine
app.set('view engine', 'ejs');
app.set('views', './views');

// Ensure uploads directory exists
const uploadsDir = path.join(__dirname, 'uploads');
fs.ensureDirSync(uploadsDir);

// Simple user storage (in production, use a proper database)
const users = [
  {
    id: 1,
    username: 'admin',
    email: 'admin@educat.com',
    password: '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
    name: 'Admin User'
  },
  {
    id: 2,
    username: 'student',
    email: 'student@educat.com',
    password: '$2b$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
    name: 'Student User'
  }
];

// Initialize demo users with proper password hashing
async function initializeDemoUsers() {
  try {
    const hashedPassword = await bcrypt.hash('password', 10);
    
    users[0].password = hashedPassword;
    users[1].password = hashedPassword;
  } catch (error) {
    console.error('Error initializing demo users:', error);
  }
}

// Initialize demo users on startup
initializeDemoUsers();

// Authentication middleware
const requireAuth = (req, res, next) => {
  if (req.session.userId) {
    next();
  } else {
    req.flash('error', 'Please log in to access this page');
    res.redirect('/login');
  }
};

// Add user info to all templates and load persistent files
app.use(async (req, res, next) => {
  res.locals.user = req.session.userId ? users.find(u => u.id === req.session.userId) : null;
  res.locals.messages = req.flash();
  
  // Load user files from persistent storage if user is logged in and session doesn't have files
  if (req.session.userId && (!req.session.uploadedFiles || req.session.uploadedFiles.length === 0)) {
    try {
      const persistentFiles = await loadUserFiles(req.session.userId);
      if (persistentFiles.length > 0) {
        req.session.uploadedFiles = persistentFiles;
      }
    } catch (error) {
      console.error('Error loading user files in middleware:', error);
    }
  }
  
  next();
});

// Configure multer for file uploads
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
  }
});

const upload = multer({ 
  storage: storage,
  limits: {
    fileSize: 10 * 1024 * 1024 // 10MB limit
  },
  fileFilter: (req, file, cb) => {
    // Allow text files, PDFs, and images
    const allowedTypes = /jpeg|jpg|png|gif|pdf|txt|doc|docx/;
    const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
    const mimetype = allowedTypes.test(file.mimetype);
    
    if (mimetype && extname) {
      return cb(null, true);
    } else {
      cb(new Error('Only text files, PDFs, and images are allowed!'));
    }
  }
});

// Flowise API configuration
const FLOWISE_API_URL = process.env.FLOWISE_API_URL || 'https://flowise.suika.cc/api/v1/prediction';
const FLOWISE_CHATFLOW_ID = process.env.FLOWISE_CHATFLOW_ID || 'your-chatflow-id';

// Helper function to chunk text into smaller pieces
function chunkText(text, chunkSize = CHUNK_SIZE, overlap = CHUNK_OVERLAP) {
  const chunks = [];
  let start = 0;
  
  while (start < text.length) {
    const end = Math.min(start + chunkSize, text.length);
    const chunk = text.substring(start, end);
    
    // Only add non-empty chunks
    if (chunk.trim().length > 0) {
      chunks.push({
        content: chunk.trim(),
        metadata: {
          chunkIndex: chunks.length,
          startIndex: start,
          endIndex: end,
          totalLength: text.length
        }
      });
    }
    
    // Move start position, accounting for overlap
    start = end - overlap;
    
    // Break if we're at the end
    if (end >= text.length) break;
  }
  
  return chunks;
}

// Helper function to clean and validate document content
function validateAndCleanDocument(content, originalName) {
  // Remove excessive whitespace and normalize line endings
  let cleanContent = content
    .replace(/\r\n/g, '\n')
    .replace(/\r/g, '\n')
    .replace(/\n{3,}/g, '\n\n')
    .replace(/[ \t]{2,}/g, ' ')
    .trim();
  
  // Check document size
  if (cleanContent.length > MAX_DOCUMENT_SIZE) {
    throw new Error(`Document is too large (${cleanContent.length} characters). Maximum size is ${MAX_DOCUMENT_SIZE} characters.`);
  }
  
  // Check if document has meaningful content
  if (cleanContent.length < 50) {
    throw new Error('Document content is too short. Please upload a document with at least 50 characters.');
  }
  
  // Remove or replace problematic characters that might cause issues
  cleanContent = cleanContent
    .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') // Remove control characters
    .replace(/[^\x20-\x7E\n\t]/g, (char) => { // Replace non-printable characters
      const code = char.charCodeAt(0);
      return code > 127 ? char : ''; // Keep Unicode characters, remove other non-printable
    });
  
  return cleanContent;
}

// Helper function to generate document hash for deduplication
function generateDocumentHash(content, originalName) {
  return crypto.createHash('sha256')
    .update(content + originalName)
    .digest('hex')
    .substring(0, 16);
}

// Helper function to get document loaders from document store
async function getDocumentStoreLoaders(documentStoreId) {
  try {

    
    const headers = {
      'Content-Type': 'application/json',
      'Accept': 'application/json'
    };

    if (FLOWISE_API_KEY) {
      headers['Authorization'] = `Bearer ${FLOWISE_API_KEY}`;
    }
    
    // Get document store details which includes loaders
    const storeUrl = `${FLOWISE_BASE_URL}/api/v1/document-store/store/${documentStoreId}`;
    const response = await axios.get(storeUrl, {
      headers,
      timeout: 10000
    });
    

    
    // Parse loaders - they may come as array directly or as JSON string
    let loaders = [];
    if (response.data.loaders) {
      if (Array.isArray(response.data.loaders)) {
        // Loaders are already an array
        loaders = response.data.loaders;

      } else if (typeof response.data.loaders === 'string') {
        // Loaders are a JSON string that needs parsing
        try {
          loaders = JSON.parse(response.data.loaders);

        } catch (parseError) {

          loaders = [];
        }
      } else {

        loaders = [];
      }
    }
    
    return {
      store: response.data,
      loaders: loaders
    };
  } catch (error) {
    console.error('Error getting document store loaders:', {
      error: error.message,
      response: error.response ? {
        status: error.response.status,
        data: error.response.data
      } : 'No response'
    });
    return null;
  }
}

// Helper function to upsert document to Flowise using FormData (direct file upload)
async function upsertDocumentToFlowiseFormData(fileInfo, documentMetadata) {

  
  try {
    // Create FormData for file upload
    const FormData = require('form-data');
    const formData = new FormData();
    
    // Read the file and append to FormData
    const filePath = path.isAbsolute(fileInfo.path) ? fileInfo.path : path.join(__dirname, fileInfo.path);
    const fileStream = fs.createReadStream(filePath);
    
    // Try to get existing document store info to find existing loaders
    const storeInfo = await getDocumentStoreLoaders(FLOWISE_DOCUMENT_STORE_ID);
    let docId = null;
    let useExistingLoader = false;
    
    if (storeInfo && storeInfo.loaders && storeInfo.loaders.length > 0) {
      // Use the first existing loader ID, but only if replaceExisting is true
      docId = storeInfo.loaders[0].id || storeInfo.loaders[0].loaderId;
      useExistingLoader = true;


    } else {
      // Create a new loader by letting Flowise auto-generate or create new store

    }
    
    // Append form fields following the Flowise API structure
    formData.append('files', fileStream, {
      filename: fileInfo.originalName,
      contentType: fileInfo.mimetype
    });
    
    // Only append docId if we have an existing loader, otherwise let Flowise create new
    if (useExistingLoader && docId) {
      formData.append('docId', docId);
      formData.append('replaceExisting', 'true');
    } else {
      // For new documents, don't specify docId and create new store entry
      formData.append('replaceExisting', 'false');
      formData.append('createNewDocStore', 'true');
    }
    
    formData.append('splitter', JSON.stringify({
      "config": {
        "chunkSize": CHUNK_SIZE,
        "chunkOverlap": CHUNK_OVERLAP
      }
    }));
    
    // Add metadata
    const metadata = {
      documentId: documentMetadata.documentId,
      originalName: documentMetadata.originalName,
      uploadDate: documentMetadata.uploadDate,
      userId: documentMetadata.userId,
      source: 'EduCat',
      fileSize: fileInfo.size,
      mimetype: fileInfo.mimetype
    };
    formData.append('metadata', JSON.stringify(metadata));
    
    // Don't duplicate the replaceExisting and createNewDocStore - they're set above
    
    // Prepare the upsert URL
    const upsertUrl = `${FLOWISE_BASE_URL}/api/v1/document-store/upsert/${FLOWISE_DOCUMENT_STORE_ID}`;

    
    // Prepare headers
    const headers = {
      ...formData.getHeaders()
    };
    
    if (FLOWISE_API_KEY) {
      headers['Authorization'] = `Bearer ${FLOWISE_API_KEY}`;
    }
    


    
    // Make the request using axios with FormData
    const response = await axios.post(upsertUrl, formData, {
      headers,
      timeout: 120000, // 2 minute timeout for large files
      maxContentLength: Infinity,
      maxBodyLength: Infinity
    });
    

    
    return {
      success: true,
      totalChunks: 1, // FormData uploads are treated as single operations
      successfulChunks: 1,
      failedChunks: 0,
      results: [{
        chunkIndex: 0,
        success: true,
        response: response.data
      }],
      errors: []
    };
    
  } catch (error) {
    console.error('Flowise FormData upsert failed:', {
      error: error.message,
      response: error.response ? {
        status: error.response.status,
        statusText: error.response.statusText,
        data: error.response.data
      } : 'No response',
      config: error.config ? {
        url: error.config.url,
        method: error.config.method
      } : 'No config'
    });
    
    // Fall back to local storage if Flowise fails

    
    try {
      const documentData = {
        id: documentMetadata.documentId,
        fileInfo: fileInfo,
        metadata: documentMetadata,
        storedAt: new Date().toISOString(),
        fallbackReason: 'flowise_formdata_upsert_failed'
      };
      
      const documentsDir = path.join(__dirname, 'data', 'documents');
      await fs.ensureDir(documentsDir);
      const documentPath = path.join(documentsDir, `${documentMetadata.documentId}.json`);
      await fs.writeJSON(documentPath, documentData, { spaces: 2 });
      

      
      return {
        success: true,
        totalChunks: 1,
        successfulChunks: 1,
        failedChunks: 0,
        results: [{
          chunkIndex: 0,
          success: true,
          response: { status: 'stored_locally', message: 'Fallback to local storage' }
        }],
        errors: []
      };
      
    } catch (fallbackError) {
      console.error('Local storage fallback also failed:', fallbackError);
      return {
        success: false,
        totalChunks: 1,
        successfulChunks: 0,
        failedChunks: 1,
        results: [],
        errors: [{
          chunkIndex: 0,
          error: `Flowise FormData upsert failed: ${error.message}. Local fallback failed: ${fallbackError.message}`,
          chunk: 'Complete document'
        }]
      };
    }
  }
}

// Routes
app.get('/', (req, res) => {
  res.render('index', { 
    title: 'EduCat - AI-Powered Note Revision',
    messages: req.flash()
  });
});

// Authentication routes
app.get('/login', (req, res) => {
  if (req.session.userId) {
    return res.redirect('/dashboard');
  }
  res.render('login', { 
    title: 'Login - EduCat',
    messages: req.flash()
  });
});

app.post('/login', async (req, res) => {
  try {
    const { username, password } = req.body;
    
    if (!username || !password) {
      req.flash('error', 'Please provide both username and password');
      return res.redirect('/login');
    }
    
    const user = users.find(u => u.username === username || u.email === username);
    
    if (!user) {
      req.flash('error', 'Invalid username or password');
      return res.redirect('/login');
    }
    
    const isValidPassword = await bcrypt.compare(password, user.password);
    
    if (!isValidPassword) {
      req.flash('error', 'Invalid username or password');
      return res.redirect('/login');
    }
    
    req.session.userId = user.id;
    req.flash('success', `Welcome back, ${user.name}!`);
    res.redirect('/dashboard');
  } catch (error) {
    console.error('Login error:', error);
    req.flash('error', 'An error occurred during login');
    res.redirect('/login');
  }
});

app.get('/register', (req, res) => {
  if (req.session.userId) {
    return res.redirect('/dashboard');
  }
  res.render('register', { 
    title: 'Register - EduCat',
    messages: req.flash()
  });
});

app.post('/register', async (req, res) => {
  try {
    const { username, email, password, confirmPassword, name } = req.body;
    
    if (!username || !email || !password || !confirmPassword || !name) {
      req.flash('error', 'Please fill in all fields');
      return res.redirect('/register');
    }
    
    if (password !== confirmPassword) {
      req.flash('error', 'Passwords do not match');
      return res.redirect('/register');
    }
    
    if (password.length < 6) {
      req.flash('error', 'Password must be at least 6 characters long');
      return res.redirect('/register');
    }
    
    // Check if user already exists
    const existingUser = users.find(u => u.username === username || u.email === email);
    if (existingUser) {
      req.flash('error', 'Username or email already exists');
      return res.redirect('/register');
    }
    
    // Hash password
    const hashedPassword = await bcrypt.hash(password, 10);
    
    // Create new user
    const newUser = {
      id: users.length + 1,
      username,
      email,
      password: hashedPassword,
      name
    };
    
    users.push(newUser);
    
    req.session.userId = newUser.id;
    req.flash('success', `Welcome to EduCat, ${newUser.name}!`);
    res.redirect('/dashboard');
  } catch (error) {
    console.error('Registration error:', error);
    req.flash('error', 'An error occurred during registration');
    res.redirect('/register');
  }
});

app.get('/logout', (req, res) => {
  req.session.destroy((err) => {
    if (err) {
      console.error('Logout error:', err);
    }
    res.redirect('/');
  });
});

app.get('/upload', requireAuth, (req, res) => {
  res.render('upload', { 
    title: 'Upload Your Notes - EduCat'
  });
});

app.post('/upload', requireAuth, upload.single('noteFile'), async (req, res) => {
  try {

    
    if (!req.file) {

      return res.status(400).json({ 
        success: false, 
        error: 'No file uploaded' 
      });
    }

    const fileInfo = {
      id: uuidv4(),
      originalName: req.file.originalname,
      filename: req.file.filename,
      path: req.file.path,
      size: req.file.size,
      mimetype: req.file.mimetype,
      uploadDate: new Date().toISOString(),
      userId: req.session.userId,
      status: 'processing'
    };



    // Store initial file info in session for immediate access
    if (!req.session.uploadedFiles) {
      req.session.uploadedFiles = [];
    }
    req.session.uploadedFiles.push(fileInfo);

    // Also store in persistent storage
    await addUserFile(req.session.userId, fileInfo);



    // Send immediate response to prevent timeout
    res.json({ 
      success: true, 
      message: 'File uploaded successfully! Processing document...',
      fileInfo: fileInfo,
      processing: true
    });



    // Process document asynchronously
    processDocumentAsync(fileInfo, req.session.userId, req.session);
    
  } catch (error) {
    console.error('Upload error:', error);
    res.status(500).json({ 
      success: false, 
      error: 'Upload failed',
      details: error.message
    });
  }
});

// Async function to process document and upsert to Flowise using FormData
async function processDocumentAsync(fileInfo, userId, session) {
  try {

    
    // Find the file in the session to update it by reference
    const sessionFile = session.uploadedFiles.find(f => f.id === fileInfo.id);
    if (!sessionFile) {
      return;
    }
    

    
    // Create document metadata
    const documentMetadata = {
      documentId: fileInfo.id,
      originalName: fileInfo.originalName,
      uploadDate: fileInfo.uploadDate,
      userId: userId,
      fileSize: fileInfo.size,
      fileInfo: fileInfo // Pass file info for progress tracking
    };
    

    
    // Initialize processing result
    sessionFile.processingResult = {
      totalChunks: 1, // FormData uploads are single operations
      successfulChunks: 0,
      failedChunks: 0,
      startedAt: new Date().toISOString(),
      status: 'uploading_to_flowise'
    };
    

    
    // Upsert document to Flowise using FormData
    const upsertResult = await upsertDocumentToFlowiseFormData(fileInfo, documentMetadata);
    

      // Update session file with processing results
    sessionFile.status = upsertResult.success ? 'processed' : 'failed';
    sessionFile.processingProgress = null; // Clear progress when done
    sessionFile.processingResult = {
      totalChunks: upsertResult.totalChunks,
      successfulChunks: upsertResult.successfulChunks,
      failedChunks: upsertResult.failedChunks,
      processedAt: new Date().toISOString(),
      startedAt: sessionFile.processingResult.startedAt,
      duration: Date.now() - new Date(sessionFile.processingResult.startedAt).getTime(),
      method: 'formdata'
    };
    
    if (upsertResult.errors.length > 0) {
      sessionFile.processingErrors = upsertResult.errors;
    }

    // Update persistent storage
    await updateUserFile(userId, fileInfo.id, {
      status: sessionFile.status,
      processingResult: sessionFile.processingResult,
      processingErrors: sessionFile.processingErrors
    });
    

    
    // Verify the session file was updated

    
    // Force session save since we modified it in an async context
    session.save((err) => {
      if (err) {
        console.error('Error saving session after document processing:', err);
      } else {

      }
    });
    
    // Log final upsert verification

    
  } catch (error) {
    console.error(`Error processing document ${fileInfo.originalName}:`, error);
    
    // Find the file in the session to update it with error
    const sessionFile = session.uploadedFiles.find(f => f.id === fileInfo.id);
    if (sessionFile) {
      sessionFile.status = 'failed';
      sessionFile.processingError = error.message;
      sessionFile.processingResult = sessionFile.processingResult || {};
      sessionFile.processingResult.failedAt = new Date().toISOString();

      // Update persistent storage
      await updateUserFile(userId, fileInfo.id, {
        status: 'failed',
        processingError: error.message,
        processingResult: sessionFile.processingResult
      });

      
      // Force session save since we modified it in an async context
      session.save((err) => {
        if (err) {
          console.error('Error saving session after processing error:', err);
        } else {

        }
      });
    }
  }
}

app.get('/revise/:fileId', requireAuth, async (req, res) => {
  try {
    const fileId = req.params.fileId;
    const files = req.session.uploadedFiles || [];
    const file = files.find(f => f.id === fileId);
    
    if (!file) {
      return res.status(404).render('error', { 
        title: 'File Not Found',
        error: 'File not found'
      });
    }

    // Read file content
    const fileContent = await fs.readFile(file.path, 'utf-8');
    
    res.render('revise', { 
      title: 'Revise Notes - EduCat',
      file: file,
      content: fileContent
    });
  } catch (error) {
    console.error('Error loading file:', error);
    res.status(500).render('error', { 
      title: 'Error',
      error: 'Failed to load file'
    });
  }
});

app.post('/api/revise', requireAuth, async (req, res) => {
  try {
    const { content, revisionType, fileId } = req.body;
    
    let prompt = '';
    let contextContent = content;
    
    // If fileId is provided, try to get additional context from stored document
    if (fileId) {
      try {
        const documentPath = path.join(__dirname, 'data', 'documents', `${fileId}.json`);
        if (await fs.pathExists(documentPath)) {
          const documentData = await fs.readJSON(documentPath);
          contextContent = documentData.content;

        }
      } catch (error) {

      }
    }
    
    switch (revisionType) {
      case 'summarize':
        prompt = `Please summarize the following notes in a clear and concise manner:\n\n${contextContent}`;
        break;
      case 'improve':
        prompt = `Please improve and enhance the following notes, making them more comprehensive and well-structured:\n\n${contextContent}`;
        break;
      case 'questions':
        prompt = `Based on the following notes, generate study questions that would help test understanding:\n\n${contextContent}`;
        break;
      default:
        prompt = `Please help improve these notes:\n\n${contextContent}`;
    }

    // Call Flowise API
    const response = await axios.post(`${FLOWISE_API_URL}/${FLOWISE_CHATFLOW_ID}`, {
      question: prompt,
      history: []
    });

    res.json({ 
      success: true, 
      revisedContent: response.data.text || response.data.answer || 'No response received'
    });
  } catch (error) {
    console.error('Revision error:', error);
    res.status(500).json({ 
      error: 'Failed to revise notes',
      details: error.message
    });
  }
});

app.get('/chat', requireAuth, (req, res) => {
  // Initialize chat history if it doesn't exist
  if (!req.session.chatHistory) {
    req.session.chatHistory = [];
  }
  
  // Initialize chat session ID if it doesn't exist
  if (!req.session.chatSessionId) {
    req.session.chatSessionId = `educat-${req.session.userId}-${Date.now()}`;

  }
  
  res.render('chat', { 
    title: 'Chat with EduCat AI',
    chatHistory: req.session.chatHistory
  });
});

app.post('/api/chat', requireAuth, async (req, res) => {
  try {
    const { message } = req.body;
    
    // Initialize chat history in session if it doesn't exist
    if (!req.session.chatHistory) {
      req.session.chatHistory = [];
    }
    
    // Initialize or get persistent chat session ID for this user
    if (!req.session.chatSessionId) {
      req.session.chatSessionId = `${req.session.userId}-${Date.now()}`;

    }
    

    
    // Prepare the request payload for Flowise with sessionId and chatId
    const flowisePayload = {
      question: message,
      sessionId: req.session.chatSessionId
    };
    
    // Add chatId if we have one from previous conversations
    if (req.session.chatId) {
      flowisePayload.chatId = req.session.chatId;

    }
    

    
    // Call Flowise API for chat with session history and sessionId
    const response = await axios.post(`${FLOWISE_API_URL}/${FLOWISE_CHATFLOW_ID}`, flowisePayload);



    const aiResponse = response.data.text || response.data.answer || 'No response received';
    
    // Save the chatId from Flowise response for future requests
    if (response.data.chatId) {
      req.session.chatId = response.data.chatId;

    }
    
    // Add the conversation to session history
    req.session.chatHistory.push({
      human: message,
      ai: aiResponse
    });
    
    // Save session explicitly since we modified it
    req.session.save((err) => {
      if (err) {
        console.error('Error saving chat session:', err);
      }
    });
    


    res.json({ 
      success: true, 
      response: aiResponse
    });
  } catch (error) {
    console.error('Chat error:', error);
    res.status(500).json({ 
      success: false,
      error: 'Failed to get chat response',
      details: error.message
    });
  }
});

// Get chat history from session
app.get('/api/chat/history', requireAuth, (req, res) => {
  try {
    const chatHistory = req.session.chatHistory || [];

    
    res.json({
      success: true,
      history: chatHistory
    });
  } catch (error) {
    console.error('Error getting chat history:', error);
    res.status(500).json({
      success: false,
      error: 'Failed to get chat history',
      details: error.message
    });
  }
});

// Clear chat history
app.delete('/api/chat/history', requireAuth, (req, res) => {
  try {
    req.session.chatHistory = [];
    // Reset the session ID to start a fresh conversation
    req.session.chatSessionId = `${req.session.userId}-${Date.now()}`;
    // Clear the Flowise chatId
    delete req.session.chatId;
    
    req.session.save((err) => {
      if (err) {
        console.error('Error clearing chat session:', err);
        return res.status(500).json({
          success: false,
          error: 'Failed to clear chat history'
        });
      }
      

      res.json({
        success: true,
        message: 'Chat history cleared'
      });
    });
  } catch (error) {
    console.error('Error clearing chat history:', error);
    res.status(500).json({
      success: false,
      error: 'Failed to clear chat history',
      details: error.message
    });
  }
});

app.get('/dashboard', requireAuth, async (req, res) => {
  try {
    // Load persistent files for this user
    const persistentFiles = await loadUserFiles(req.session.userId);
    
    // Merge with session files (in case there are newly uploaded files not yet saved)
    const sessionFiles = req.session.uploadedFiles || [];
    const allFiles = [...persistentFiles];
    
    // Add any session files that aren't already in persistent storage
    sessionFiles.forEach(sessionFile => {
      if (!persistentFiles.find(f => f.id === sessionFile.id)) {
        allFiles.push(sessionFile);
      }
    });
    
    // Update session with merged files for current session use
    req.session.uploadedFiles = allFiles;
    
    res.render('dashboard', { 
      title: 'Dashboard - EduCat',
      files: allFiles
    });
  } catch (error) {
    console.error('Error loading dashboard:', error);
    res.render('dashboard', { 
      title: 'Dashboard - EduCat',
      files: req.session.uploadedFiles || []
    });
  }
});

// File management endpoints
app.get('/api/files/:fileId/preview', requireAuth, async (req, res) => {
  try {
    const fileId = req.params.fileId;
    const files = req.session.uploadedFiles || [];
    const file = files.find(f => f.id === fileId);
    
    if (!file) {
      return res.status(404).json({ success: false, error: 'File not found' });
    }

    // Read file content
    const filePath = path.join(__dirname, file.path);
    const fileContent = await fs.readFile(filePath, 'utf-8');
    
    res.json({
      success: true,
      file: {
        id: file.id,
        originalName: file.originalName,
        size: file.size,
        uploadDate: file.uploadDate,
        content: fileContent
      }
    });
  } catch (error) {
    console.error('Error previewing file:', error);
    res.status(500).json({ 
      success: false, 
      error: 'Failed to preview file',
      details: error.message
    });
  }
});

app.delete('/api/files/:fileId', requireAuth, async (req, res) => {
  try {
    const fileId = req.params.fileId;
    const files = req.session.uploadedFiles || [];
    const fileIndex = files.findIndex(f => f.id === fileId);
    
    if (fileIndex === -1) {
      return res.status(404).json({ success: false, error: 'File not found' });
    }

    const file = files[fileIndex];
    
    // Delete the physical file
    const filePath = path.join(__dirname, file.path);
    if (await fs.pathExists(filePath)) {
      await fs.unlink(filePath);
    }
    
    // Remove from session
    req.session.uploadedFiles.splice(fileIndex, 1);
    
    // Remove from persistent storage
    await removeUserFile(req.session.userId, fileId);
    

    
    res.json({
      success: true,
      message: 'File deleted successfully'
    });
  } catch (error) {
    console.error('Error deleting file:', error);
    res.status(500).json({ 
      success: false, 
      error: 'Failed to delete file',
      details: error.message
    });
  }
});

// File processing status endpoint
app.get('/api/files/:fileId/status', requireAuth, async (req, res) => {
  try {
    const fileId = req.params.fileId;
    let files = req.session.uploadedFiles || [];
    let file = files.find(f => f.id === fileId);
    
    // If not in session, try to load from persistent storage
    if (!file) {
      const persistentFiles = await loadUserFiles(req.session.userId);
      file = persistentFiles.find(f => f.id === fileId);
      
      // If found in persistent storage, add to session for future requests
      if (file) {
        if (!req.session.uploadedFiles) {
          req.session.uploadedFiles = [];
        }
        req.session.uploadedFiles.push(file);
      }
    }
    
    if (!file) {
      return res.status(404).json({ success: false, error: 'File not found' });
    }
    
    res.json({
      success: true,
      file: {
        id: file.id,
        originalName: file.originalName,
        status: file.status,
        uploadDate: file.uploadDate,
        processingResult: file.processingResult,
        processingError: file.processingError,
        processingErrors: file.processingErrors
      }
    });
  } catch (error) {
    console.error('Error getting file status:', error);
    res.status(500).json({ 
      success: false, 
      error: 'Failed to get file status',
      details: error.message
    });
  }
});

// Retry processing endpoint
app.post('/api/files/:fileId/retry', requireAuth, async (req, res) => {
  try {
    const fileId = req.params.fileId;
    const files = req.session.uploadedFiles || [];
    const file = files.find(f => f.id === fileId);
    
    if (!file) {
      return res.status(404).json({ success: false, error: 'File not found' });
    }
    
    if (file.status === 'processing') {
      return res.status(400).json({ success: false, error: 'File is already being processed' });
    }
    
    // Reset file status for retry
    file.status = 'processing';
    file.processingResult = null;
    file.processingError = null;
    file.processingErrors = null;
    
    // Start processing asynchronously
    processDocumentAsync(file, req.session.userId, req.session);
    
    res.json({
      success: true,
      message: 'Processing retry initiated'
    });
  } catch (error) {
    console.error('Error retrying processing:', error);
    res.status(500).json({ 
      success: false, 
      error: 'Failed to retry processing',
      details: error.message
    });
  }
});

// Bulk processing status endpoint
app.get('/api/files/status/all', requireAuth, async (req, res) => {
  try {
    // Load persistent files and merge with session
    const persistentFiles = await loadUserFiles(req.session.userId);
    const sessionFiles = req.session.uploadedFiles || [];
    
    // Merge files, preferring session data for current uploads
    const allFiles = [...persistentFiles];
    sessionFiles.forEach(sessionFile => {
      const existingIndex = allFiles.findIndex(f => f.id === sessionFile.id);
      if (existingIndex !== -1) {
        // Update existing with session data (more current)
        allFiles[existingIndex] = sessionFile;
      } else {
        // Add new session file
        allFiles.push(sessionFile);
      }
    });
    
    const statusSummary = allFiles.map(file => ({
      id: file.id,
      originalName: file.originalName,
      status: file.status,
      uploadDate: file.uploadDate,
      processingResult: file.processingResult ? {
        totalChunks: file.processingResult.totalChunks,
        successfulChunks: file.processingResult.successfulChunks,
        failedChunks: file.processingResult.failedChunks,
        processedAt: file.processingResult.processedAt
      } : null
    }));
    
    const summary = {
      totalFiles: allFiles.length,
      processing: allFiles.filter(f => f.status === 'processing').length,
      processed: allFiles.filter(f => f.status === 'processed').length,
      failed: allFiles.filter(f => f.status === 'failed').length,
      files: statusSummary
    };
    
    res.json({
      success: true,
      summary: summary
    });
  } catch (error) {
    console.error('Error getting files status:', error);
    res.status(500).json({ 
      success: false, 
      error: 'Failed to get files status',
      details: error.message
    });
  }
});

app.get('/quiz', requireAuth, (req, res) => {
  res.render('quiz', { 
    title: 'AI Quiz Generator - EduCat'
  });
});

app.post('/api/generate-quiz', requireAuth, async (req, res) => {

  
  try {
    const { topic, difficulty, questionCount, quizType } = req.body;
    

    
    let prompt = '';
    switch (quizType) {
      case 'multiple-choice':
        prompt = `Generate exactly ${questionCount} multiple choice questions about "${topic}" at ${difficulty} difficulty level. 
        Each question should have 4 options (A, B, C, D). 
        Format the response as a JSON array where each question follows this exact structure:
        [
          {
            "question": "What is the capital of France?",
            "options": ["A) London", "B) Paris", "C) Berlin", "D) Madrid"],
            "correct": "B",
            "explanation": "Paris is the capital and largest city of France."
          }
        ]
        Return ONLY the JSON array, no additional text.`;
        break;
      case 'true-false':
        prompt = `Generate exactly ${questionCount} true/false questions about "${topic}" at ${difficulty} difficulty level.
        Format the response as a JSON array where each question follows this exact structure:
        [
          {
            "question": "The Earth is flat.",
            "correct": "False",
            "explanation": "The Earth is spherical, not flat."
          }
        ]
        Return ONLY the JSON array, no additional text.`;
        break;
      case 'short-answer':
        prompt = `Generate exactly ${questionCount} short answer questions about "${topic}" at ${difficulty} difficulty level.
        Format the response as a JSON array where each question follows this exact structure:
        [
          {
            "question": "What is the process by which plants make their own food?",
            "answer": "Photosynthesis",
            "keywords": ["photosynthesis", "sunlight", "chlorophyll"]
          }
        ]
        Return ONLY the JSON array, no additional text.`;
        break;
      default:
        prompt = `Generate exactly ${questionCount} multiple choice questions about "${topic}" at ${difficulty} difficulty level.`;
    }



    // Call Flowise API
    const response = await axios.post(`${FLOWISE_API_URL}/${FLOWISE_CHATFLOW_ID}`, {
      question: prompt,
      history: []
    });



    let quizData;
    try {
      const responseText = response.data.text || response.data.answer || response.data;

      
      // Try to extract JSON from the response
      let jsonString = null;
      
      // First, try to find JSON wrapped in code blocks
      const codeBlockMatch = responseText.match(/```(?:json)?\s*(\[[\s\S]*?\])\s*```/);
      if (codeBlockMatch) {
        jsonString = codeBlockMatch[1];

      } else {
        // Try to find JSON array by counting brackets
        const startIndex = responseText.indexOf('[');
        if (startIndex !== -1) {
          let bracketCount = 0;
          let endIndex = startIndex;
          
          for (let i = startIndex; i < responseText.length; i++) {
            if (responseText[i] === '[') bracketCount++;
            if (responseText[i] === ']') bracketCount--;
            if (bracketCount === 0) {
              endIndex = i;
              break;
            }
          }
          
          if (bracketCount === 0) {
            jsonString = responseText.substring(startIndex, endIndex + 1);

          }
        }
      }
      
      if (jsonString) {
        quizData = JSON.parse(jsonString);
      } else {
        quizData = generateFallbackQuiz(topic, questionCount, quizType);
      }
    } catch (parseError) {
      console.error('Quiz parsing error:', parseError);
      quizData = generateFallbackQuiz(topic, questionCount, quizType);
    }

    // Ensure quizData is always defined and is an array
    if (!quizData || !Array.isArray(quizData) || quizData.length === 0) {
      quizData = generateFallbackQuiz(topic, questionCount, quizType);
    }



    res.json({ 
      success: true, 
      quiz: quizData,
      topic: topic,
      difficulty: difficulty,
      questionCount: questionCount,
      quizType: quizType
    });
  } catch (error) {
    console.error('Quiz generation error:', error);
    console.error('Error stack:', error.stack);
    
    // Return fallback quiz on error
    const fallbackQuiz = generateFallbackQuiz(req.body.topic || 'General Knowledge', req.body.questionCount || 5, req.body.quizType || 'multiple-choice');
    res.json({ 
      success: true, 
      quiz: fallbackQuiz,
      topic: req.body.topic || 'General Knowledge',
      difficulty: req.body.difficulty || 'beginner',
      questionCount: req.body.questionCount || 5,
      quizType: req.body.quizType || 'multiple-choice'
    });
  }
});

function generateFallbackQuiz(topic, questionCount, quizType) {
  const questions = [];
  
  // Generate actual questions based on topic
  const topicQuestions = {
    'javascript': [
      {
        question: 'What is the correct way to declare a variable in JavaScript?',
        options: ['A) var myVar = 5;', 'B) variable myVar = 5;', 'C) declare myVar = 5;', 'D) int myVar = 5;'],
        correct: 'A',
        explanation: 'The var keyword is used to declare variables in JavaScript.'
      },
      {
        question: 'Which method is used to add an element to the end of an array?',
        options: ['A) push()', 'B) add()', 'C) append()', 'D) insert()'],
        correct: 'A',
        explanation: 'The push() method adds one or more elements to the end of an array.'
      },
      {
        question: 'What does === operator do in JavaScript?',
        options: ['A) Assigns a value', 'B) Compares values only', 'C) Compares values and types', 'D) Declares a constant'],
        correct: 'C',
        explanation: 'The === operator compares both value and type without type conversion.'
      },
      {
        question: 'How do you write a comment in JavaScript?',
        options: ['A) <!-- comment -->', 'B) // comment', 'C) # comment', 'D) /* comment */'],
        correct: 'B',
        explanation: 'Single-line comments in JavaScript start with //.'
      },
      {
        question: 'What is the result of typeof null in JavaScript?',
        options: ['A) "null"', 'B) "undefined"', 'C) "object"', 'D) "boolean"'],
        correct: 'C',
        explanation: 'typeof null returns "object" due to a legacy bug in JavaScript.'
      }
    ],
    'python': [
      {
        question: 'Which keyword is used to create a function in Python?',
        options: ['A) function', 'B) def', 'C) create', 'D) func'],
        correct: 'B',
        explanation: 'The def keyword is used to define functions in Python.'
      },
      {
        question: 'What is the correct way to create a list in Python?',
        options: ['A) list = (1, 2, 3)', 'B) list = {1, 2, 3}', 'C) list = [1, 2, 3]', 'D) list = <1, 2, 3>'],
        correct: 'C',
        explanation: 'Square brackets [] are used to create lists in Python.'
      },
      {
        question: 'How do you start a comment in Python?',
        options: ['A) //', 'B) #', 'C) /*', 'D) --'],
        correct: 'B',
        explanation: 'Comments in Python start with the # symbol.'
      },
      {
        question: 'What does len() function do in Python?',
        options: ['A) Returns the length of an object', 'B) Converts to lowercase', 'C) Rounds a number', 'D) Prints output'],
        correct: 'A',
        explanation: 'The len() function returns the number of items in an object.'
      },
      {
        question: 'Which of the following is a mutable data type in Python?',
        options: ['A) tuple', 'B) string', 'C) list', 'D) integer'],
        correct: 'C',
        explanation: 'Lists are mutable, meaning they can be changed after creation.'
      }
    ],
    'math': [
      {
        question: 'What is the value of π (pi) approximately?',
        options: ['A) 3.14159', 'B) 2.71828', 'C) 1.61803', 'D) 4.66920'],
        correct: 'A',
        explanation: 'π (pi) is approximately 3.14159, the ratio of circumference to diameter.'
      },
      {
        question: 'What is the derivative of x²?',
        options: ['A) x', 'B) 2x', 'C) x³', 'D) 2x²'],
        correct: 'B',
        explanation: 'Using the power rule, the derivative of x² is 2x.'
      },
      {
        question: 'What is the Pythagorean theorem?',
        options: ['A) a + b = c', 'B) a² + b² = c²', 'C) a × b = c', 'D) a² - b² = c²'],
        correct: 'B',
        explanation: 'The Pythagorean theorem states that a² + b² = c² for right triangles.'
      },
      {
        question: 'What is the factorial of 5?',
        options: ['A) 25', 'B) 120', 'C) 60', 'D) 100'],
        correct: 'B',
        explanation: '5! = 5 × 4 × 3 × 2 × 1 = 120'
      },
      {
        question: 'What is the square root of 64?',
        options: ['A) 6', 'B) 7', 'C) 8', 'D) 9'],
        correct: 'C',
        explanation: 'The square root of 64 is 8 because 8² = 64.'
      }
    ]
  };
  
  // Get appropriate questions for the topic
  const availableQuestions = topicQuestions[topic.toLowerCase()] || topicQuestions['math'];
  
  for (let i = 0; i < questionCount; i++) {
    const questionIndex = i % availableQuestions.length;
    const baseQuestion = availableQuestions[questionIndex];
    
    if (quizType === 'multiple-choice') {
      questions.push({
        question: baseQuestion.question,
        options: baseQuestion.options,
        correct: baseQuestion.correct,
        explanation: baseQuestion.explanation
      });
    } else if (quizType === 'true-false') {
      questions.push({
        question: baseQuestion.question.replace(/Which|What|How/, 'Is it true that'),
        correct: Math.random() > 0.5 ? 'True' : 'False',
        explanation: baseQuestion.explanation
      });
    } else {
      questions.push({
        question: baseQuestion.question,
        answer: baseQuestion.correct,
        keywords: [baseQuestion.correct.toLowerCase(), topic.toLowerCase()]
      });
    }
  }
  
  return questions;
}

app.post('/api/submit-quiz', requireAuth, async (req, res) => {
  try {
    const { answers, quiz, topic, difficulty, quizType } = req.body;
    
    let score = 0;
    const results = [];
    
    quiz.forEach((question, index) => {
      const userAnswer = answers[index];
      const isCorrect = userAnswer === question.correct;
      if (isCorrect) score++;
      
      results.push({
        question: question.question,
        userAnswer: userAnswer,
        correctAnswer: question.correct,
        isCorrect: isCorrect,
        explanation: question.explanation || '',
        options: question.options || null // Include options for multiple choice
      });
    });
    
    const percentage = Math.round((score / quiz.length) * 100);
    
    // Store quiz result in session
    if (!req.session.quizResults) {
      req.session.quizResults = [];
    }
    
    const quizResult = {
      id: uuidv4(),
      topic: topic,
      score: score,
      total: quiz.length,
      percentage: percentage,
      date: new Date().toISOString(),
      results: results,
      userId: req.session.userId,
      difficulty: difficulty || 'beginner',
      quizType: quizType || 'multiple-choice'
    };
    
    // Store quiz result in session (for immediate use)
    req.session.quizResults.push(quizResult);
    
    // Store quiz result persistently
    await addQuizResult(req.session.userId, quizResult);
    

    
    res.json({ 
      success: true, 
      score: score,
      total: quiz.length,
      percentage: percentage,
      results: results,
      quizId: quizResult.id
    });
  } catch (error) {
    console.error('Quiz submission error:', error);
    res.status(500).json({ 
      error: 'Failed to submit quiz',
      details: error.message
    });
  }
});

// User file storage persistence
const USER_FILES_DIR = path.join(__dirname, 'data', 'user-files');

// Ensure user files directory exists
async function ensureUserFilesDirectory() {
  await fs.ensureDir(USER_FILES_DIR);
}

// Save user files to persistent storage
async function saveUserFiles(userId, files) {
  try {
    await ensureUserFilesDirectory();
    const userFilePath = path.join(USER_FILES_DIR, `user-${userId}-files.json`);
    await fs.writeJSON(userFilePath, files, { spaces: 2 });
  } catch (error) {
    console.error('Error saving user files:', error);
  }
}

// Load user files from persistent storage
async function loadUserFiles(userId) {
  try {
    await ensureUserFilesDirectory();
    const userFilePath = path.join(USER_FILES_DIR, `user-${userId}-files.json`);
    if (await fs.pathExists(userFilePath)) {
      const files = await fs.readJSON(userFilePath);
      return files || [];
    }
    return [];
  } catch (error) {
    console.error('Error loading user files:', error);
    return [];
  }
}

// Add a file to user's persistent storage
async function addUserFile(userId, fileInfo) {
  const userFiles = await loadUserFiles(userId);
  userFiles.push(fileInfo);
  await saveUserFiles(userId, userFiles);
}

// Update a file in user's persistent storage
async function updateUserFile(userId, fileId, updates) {
  const userFiles = await loadUserFiles(userId);
  const fileIndex = userFiles.findIndex(f => f.id === fileId);
  if (fileIndex !== -1) {
    userFiles[fileIndex] = { ...userFiles[fileIndex], ...updates };
    await saveUserFiles(userId, userFiles);
  }
}

// Remove a file from user's persistent storage
async function removeUserFile(userId, fileId) {
  const userFiles = await loadUserFiles(userId);
  const filteredFiles = userFiles.filter(f => f.id !== fileId);
  await saveUserFiles(userId, filteredFiles);
}

// Quiz results persistence
const QUIZ_RESULTS_FILE = path.join(__dirname, 'data', 'quiz-results.json');

// Ensure data directory exists
async function ensureDataDirectory() {
  await fs.ensureDir(path.join(__dirname, 'data'));
}

// Load quiz results from file
async function loadQuizResults() {
  try {
    await ensureDataDirectory();
    if (await fs.pathExists(QUIZ_RESULTS_FILE)) {
      const data = await fs.readJSON(QUIZ_RESULTS_FILE);
      return data || {};
    }
    return {};
  } catch (error) {
    console.error('Error loading quiz results:', error);
    return {};
  }
}

// Save quiz results to file
async function saveQuizResults(results) {
  try {
    await ensureDataDirectory();
    await fs.writeJSON(QUIZ_RESULTS_FILE, results, { spaces: 2 });
  } catch (error) {
    console.error('Error saving quiz results:', error);
  }
}

// Add quiz result for user
async function addQuizResult(userId, quizResult) {
  const allResults = await loadQuizResults();
  if (!allResults[userId]) {
    allResults[userId] = [];
  }
  allResults[userId].push(quizResult);
  await saveQuizResults(allResults);
}

// Get quiz results for user
async function getUserQuizResults(userId) {
  const allResults = await loadQuizResults();
  return allResults[userId] || [];
}

// Error handling middleware
app.use((error, req, res, next) => {
  if (error instanceof multer.MulterError) {
    if (error.code === 'LIMIT_FILE_SIZE') {
      return res.status(400).json({ error: 'File too large. Maximum size is 10MB.' });
    }
  }
  
  console.error('Error:', error);
  res.status(500).json({ error: 'Internal server error' });
});

// Quiz history route
app.get('/quiz-history', requireAuth, async (req, res) => {
  try {
    const quizResults = await getUserQuizResults(req.session.userId);
    res.render('quiz-history', { 
      title: 'Quiz History - EduCat',
      quizResults: quizResults.reverse() // Show newest first
    });
  } catch (error) {
    console.error('Error loading quiz history:', error);
    res.render('quiz-history', { 
      title: 'Quiz History - EduCat',
      quizResults: []
    });
  }
});

// API route to clear quiz history
app.delete('/api/quiz-history', requireAuth, async (req, res) => {
  try {
    const userId = req.session.userId;
    const allResults = await loadQuizResults();
    
    // Clear quiz history for this user
    allResults[userId] = [];
    await saveQuizResults(allResults);
    

    
    res.json({
      success: true,
      message: 'Quiz history cleared successfully'
    });
  } catch (error) {
    console.error('Error clearing quiz history:', error);
    res.status(500).json({ 
      success: false, 
      error: 'Failed to clear quiz history' 
    });
  }
});

// API route to get quiz statistics
app.get('/api/quiz-stats', requireAuth, async (req, res) => {
  try {
    const quizResults = await getUserQuizResults(req.session.userId);
    
    if (quizResults.length === 0) {
      return res.json({
        success: true,
        stats: {
          totalQuizzes: 0,
          averageScore: 0,
          bestScore: 0,
          recentQuizzes: [],
          topicStats: {},
          progressChart: []
        }
      });
    }
    
    // Calculate statistics
    const totalQuizzes = quizResults.length;
    const averageScore = Math.round(quizResults.reduce((sum, quiz) => sum + quiz.percentage, 0) / totalQuizzes);
    const bestScore = Math.max(...quizResults.map(quiz => quiz.percentage));
    const recentQuizzes = quizResults.slice(-5).reverse(); // Last 5 quizzes
    
    // Topic statistics
    const topicStats = {};
    quizResults.forEach(quiz => {
      if (!topicStats[quiz.topic]) {
        topicStats[quiz.topic] = {
          count: 0,
          totalScore: 0,
          bestScore: 0
        };
      }
      topicStats[quiz.topic].count++;
      topicStats[quiz.topic].totalScore += quiz.percentage;
      topicStats[quiz.topic].bestScore = Math.max(topicStats[quiz.topic].bestScore, quiz.percentage);
    });
    
    // Calculate average for each topic
    Object.keys(topicStats).forEach(topic => {
      topicStats[topic].averageScore = Math.round(topicStats[topic].totalScore / topicStats[topic].count);
    });
    
    // Progress chart data (last 10 quizzes)
    const progressChart = quizResults.slice(-10).map((quiz, index) => ({
      quiz: index + 1,
      score: quiz.percentage,
      topic: quiz.topic,
      date: quiz.date
    }));
    
    res.json({
      success: true,
      stats: {
        totalQuizzes,
        averageScore,
        bestScore,
        recentQuizzes,
        topicStats,
        progressChart
      }
    });
  } catch (error) {
    console.error('Error getting quiz stats:', error);
    res.status(500).json({ success: false, error: 'Failed to get quiz statistics' });
  }
});

// API route to get detailed quiz results by ID
app.get('/api/quiz-details/:quizId', requireAuth, async (req, res) => {
  try {
    const quizId = req.params.quizId;
    const quizResults = await getUserQuizResults(req.session.userId);
    
    const quiz = quizResults.find(q => q.id === quizId);
    
    if (!quiz) {
      return res.status(404).json({ success: false, error: 'Quiz not found' });
    }
    
    res.json({
      success: true,
      quiz: quiz
    });
  } catch (error) {
    console.error('Error getting quiz details:', error);
    res.status(500).json({ success: false, error: 'Failed to get quiz details' });
  }
});

// File progress tracking endpoint
app.get('/api/files/:fileId/progress', requireAuth, async (req, res) => {
  try {
    const fileId = req.params.fileId;
    const files = req.session.uploadedFiles || [];
    const file = files.find(f => f.id === fileId);
    
    if (!file) {
      return res.status(404).json({ success: false, error: 'File not found' });
    }
    
    res.json({
      success: true,
      progress: {
        status: file.status,
        processingProgress: file.processingProgress || null,
        processingResult: file.processingResult || null,
        processingError: file.processingError || null
      }
    });
  } catch (error) {
    console.error('Error getting file progress:', error);
    res.status(500).json({ 
      success: false, 
      error: 'Failed to get file progress',
      details: error.message
    });
  }
});

// 404 handler
app.use((req, res) => {
  res.status(404).render('error', { 
    title: 'Page Not Found',
    error: 'The page you are looking for does not exist.'
  });
});

app.listen(PORT, () => {
  console.log(`EduCat server running on http://localhost:${PORT}`);
});




