const express = require('express');
const router = express.Router();
const db = require('../db');
const fs = require('fs');
const rangeParser = require('range-parser');
const serverError = require('../utils/serverError');
const videoManager = require('../src/video/videoManager');
const database_manager = require('../src/database/database_manager');
const storage_manager = require('../src/data/storage_manager');
const dbTester = require('../test/tester');

router.get('/videos', (req, res) => {
   const query = 'SELECT * FROM public.videos';
   db.query(query, (err, results) => {
      if (err) {
         serverError.sendError('Erreur lors de la récupération des vidéos:', res, err, 500);
      }
      res.json(results.rows);
   });
});

router.get('/videos/:id', (req, res) => {
   const videoId = req.params.id;
   if (!videoId || isNaN(videoId)) {
      return res.status(400).json({ error: 'Invalid video ID' });
   }
   const query = 'SELECT * FROM public.videos WHERE id = $1';
   db.query(query, [videoId], (err, results) => {
      if (err) {
         serverError.sendError('Erreur lors de la récupération de la vidéo:', res, err, 500);
      }
      res.json(results.rows);
   });
});

router.post('/videos', async (req, res) => {
   const { project_id, measurement_ids, name, resolution, duration } = req.body;
   console.log('Creating video:', req.body);
   if (!project_id || !measurement_ids || !name || !resolution || !duration) {
      return res.status(400).json({ error: 'Tous les champs sont requis.' });
   }

   console.log('Creating video with measurements:', measurement_ids);

   try {
      const query = await database_manager.video.create_video(project_id, measurement_ids, name, resolution, duration);
      const videoId = query.id;
      if (!videoId) {  
         return res.status(500).json({ error: 'Erreur lors de la création de la vidéo' });
      }
      console.log('Vidéo créée avec succès:', videoId);
      
      // Start rendering the video immediately after creation
      // const result = await db.query(
      //    'SELECT measurement_ids, project_id, duration FROM public.videos WHERE id = $1',
      //    [videoId]
      // );

      // if (result.rows.length === 0) {
      //    return res.status(404).json({ error: 'Vidéo non trouvée' });
      // }

      // récupérer les informations de la vidéo
      const result = await database_manager.video.get_video_by_id(videoId);

      if (!result) {
         return res.status(404).json({ error: 'Vidéo non trouvée' });
      }

      const videoDuration = result.duration;
      const videoMeasurementIds = result.measurement_ids;
      const videoProjectId = result.project_id;
      
      const pathList = await storage_manager.measurement.get_path_list(videoMeasurementIds, project_id);
      if (!pathList || pathList.length === 0) {
         return res.status(404).json({ error: 'Aucun chemin trouvé pour les mesures' });
      }
      
      // parser la résolution (ex: 1920x1080)
      const [res_width, res_height] = resolution.split('x').map(Number);
      if (isNaN(res_width) || isNaN(res_height)) {
         return res.status(400).json({ error: 'Invalid resolution format. Use WIDTHxHEIGHT (e.g., 1920x1080)' });
      }

      // Start background processing
      videoManager.createVideoWithList(videoProjectId, pathList, videoDuration, videoId, res_width, res_height)
         .then(videoFile => {
            console.log('Rendu vidéo terminé:', videoFile);
            return database_manager.video.update_video_file_path_by_id(videoId, videoFile);
         })
         .catch(error => {
            console.error('Échec du rendu vidéo:', error);
         });

      // Immediate response
      res.json({
         message: 'Vidéo créée avec succès et le rendu a démarré',
         id: videoId
      });

   } catch (err) {
      console.error('Erreur lors de la création de la vidéo:', err);
      res.status(500).json({ error: 'Erreur lors de la création de la vidéo' });
   }
});


router.delete('/videos/:id', (req, res) => {
   const videoId = req.params.id;
   if (!videoId || isNaN(videoId)) {
      return res.status(400).json({ error: 'Invalid video ID' });
   }

   const query = 'SELECT video_file FROM public.videos WHERE id = $1';
   db.query(query, [videoId], (err, results) => {
      if (err) {
         return serverError.sendError('Error getting video:', res, err, 500);
      }
      if (results.rows.length === 0) {
         return res.status(404).json({ error: 'Video not found' });
      }

      const videoFile = results.rows[0].video_file;
      console.log('Deleting video file:', videoFile);

      if(videoFile==null){
         console.log('No video file to delete');
         database_manager.video.delete_video_by_id(videoId).then(() => {
            res.json({ message: 'Vidéo supprimée avec succès' });
         }).catch(err => {
            console.error('Erreur lors de la suppression de la vidéo:', err);
            res.status(500).json({ error: 'Erreur lors de la suppression de la vidéo' });
         });

      } else {
         fs.unlink(videoFile, (err) => {
            if (err) {
               console.error('Error deleting video file:', err);
               return res.status(500).json({ error: 'Error deleting video file' });
            }
            database_manager.video.delete_video_by_id(videoId).then(() => {
               res.json({ message: 'Vidéo supprimée avec succès' });
            }).catch(err => {
               console.error('Erreur lors de la suppression de la vidéo:', err);
               res.status(500).json({ error: 'Erreur lors de la suppression de la vidéo' });
            });
         });
      }
   });
});

router.get('/videos/file/:video_id', (req, res) => {
   const videoId = req.params.video_id;
   const query = 'SELECT video_file, status FROM public.videos WHERE id = $1';

   db.query(query, [videoId], (err, results) => {
      if (err) {
         console.error('Error getting video:', err);
         return serveFallbackVideo(res);
      }
      if (results.rows.length === 0) {
         console.error('Video not found');
         return serveFallbackVideo(res);
      }

      const video = results.rows[0];
      if (video.status === 0) {
         return res.status(400).json({ error: 'Video not yet produced' });
      }

      let videoPath = video.video_file;

      if (!videoPath) {
         console.error('Video file path is null or undefined');
         videoPath = dbTester.getCatVideo();
      }

      // Check if the video file exists
      fs.access(videoPath, fs.constants.F_OK, (err) => {
         if (err) {
            console.error('Video file not found:', err);
            videoPath = dbTester.getCatVideo();
         }

         const stat = fs.statSync(videoPath);
         const fileSize = stat.size;
         const range = req.headers.range;

         if (range) {
            const parts = rangeParser(fileSize, range);
            const start = parts[0].start;
            const end = parts[0].end;
            const chunksize = (end - start) + 1;
            const file = fs.createReadStream(videoPath, { start, end });
            const head = {
               'Content-Range': `bytes ${start}-${end}/${fileSize}`,
               'Accept-Ranges': 'bytes',
               'Content-Length': chunksize,
               'Content-Type': 'video/mp4',
            };
            res.writeHead(206, head);
            file.pipe(res);
         } else {
            const head = {
               'Content-Length': fileSize,
               'Content-Type': 'video/mp4',
            };
            res.writeHead(200, head);
            fs.createReadStream(videoPath).pipe(res);
         }
      });
   });
});

function serveFallbackVideo() {
   return dbTester.getCatVideo();
}

router.get('/videos/progress/:video_id', async (req, res) => {
   try {
       const result = await db.query(`
           SELECT 
               progress, 
               EXTRACT(EPOCH FROM (NOW() - started_at)) as elapsed,
               eta,
               status
           FROM public.videos 
           WHERE id = $1
       `, [req.params.video_id]);

       if (result.rows.length === 0) {
           return res.status(404).json({ error: 'Vidéo non trouvée' });
       }

       const video = result.rows[0];
       res.json({
           progress: video.progress,
           elapsed: video.elapsed,
           eta: video.eta,
           status: this.getStatusLabel(video.status)
       });

   } catch (error) {
       console.error(error);
       res.status(500).json({ error: 'Erreur de récupération' });
   }
});

// function getStatusLabel(status) {
//    const statusMap = {
//        0: 'En attente',
//        1: 'Terminé',
//        2: 'Échec',
//        3: 'En cours'
//    };
//    return statusMap[status] || 'Inconnu';
// }


router.get('/cat', (_, res) => {
   const videoPath = dbTester.getCatVideo();
   fs.access(videoPath, fs.constants.F_OK, (err) => {
      if (err) {
         console.error('Video not found:', err);
         return res.status(404).json({ error: 'Video not found' });
      }
      res.download(videoPath);
   });
});

module.exports = router;
