const path = require('path');
const fs = require('fs');
const { v4: uuidv4 } = require('uuid');

class VideoController {
  constructor(baseUploadPath = 'uploads/videos') {
    this.basePath = path.resolve(baseUploadPath);
    this._ensureDirectory(this.basePath);
  }

  // ============ PRIVATE METHODS ============

  _ensureDirectory(dir) {
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
  }

  _isVideoFile(filename) {
    return /\.(mp4|webm|ogg|mov|avi|mkv)$/i.test(filename);
  }

  _getFileInfo(filePath, relativePath = '') {
    const stat = fs.statSync(filePath);
    const filename = path.basename(filePath);

    return {
      id: uuidv4(),
      filename,
      folder: relativePath,
      path: `/videos/${relativePath ? relativePath + '/' : ''}${filename}`,
      size: stat.size,
      createdAt: stat.birthtime.toISOString(),
      modifiedAt: stat.mtime.toISOString(),
    };
  }

  _scanFolders(dir, relativePath = '') {
    const folders = [];

    if (!fs.existsSync(dir)) return folders;

    const items = fs.readdirSync(dir);

    items.forEach((item) => {
      const fullPath = path.join(dir, item);
      const relPath = relativePath ? `${relativePath}/${item}` : item;

      if (fs.statSync(fullPath).isDirectory()) {
        folders.push({
          name: item,
          path: relPath,
          level: relPath.split('/').length,
        });
        // Ricorsione per sottocartelle
        folders.push(...this._scanFolders(fullPath, relPath));
      }
    });

    return folders;
  }

  // ============ FOLDER METHODS ============

  /**
   * Ottiene tutte le cartelle
   */
  getFolders = async (req, res) => {
    try {
      const folders = this._scanFolders(this.basePath);

      res.json({
        success: true,
        data: { folders },
        message: 'Cartelle recuperate con successo',
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Crea una nuova cartella
   */
  createFolder = async (req, res) => {
    try {
      const { folderName, parentPath = '' } = req.body;

      if (!folderName || !folderName.trim()) {
        return res.status(400).json({
          success: false,
          error: 'Nome cartella richiesto',
        });
      }

      // Sanitizza il nome cartella
      const sanitizedName = folderName.replace(/[<>:"/\\|?*]/g, '_').trim();

      const basePath = parentPath ? path.join(this.basePath, parentPath) : this.basePath;

      const newFolderPath = path.join(basePath, sanitizedName);

      if (fs.existsSync(newFolderPath)) {
        return res.status(409).json({
          success: false,
          error: 'La cartella esiste già',
        });
      }

      fs.mkdirSync(newFolderPath, { recursive: true });

      const folderData = {
        name: sanitizedName,
        path: parentPath ? `${parentPath}/${sanitizedName}` : sanitizedName,
        createdAt: new Date().toISOString(),
      };

      res.status(201).json({
        success: true,
        data: { folder: folderData },
        message: 'Cartella creata con successo',
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Rinomina una cartella
   */
  renameFolder = async (req, res) => {
    try {
      const { folderPath } = req.params;
      const { newName } = req.body;

      if (!newName || !newName.trim()) {
        return res.status(400).json({
          success: false,
          error: 'Nuovo nome richiesto',
        });
      }

      const sanitizedName = newName.replace(/[<>:"/\\|?*]/g, '_').trim();
      const oldPath = path.join(this.basePath, folderPath);
      const parentDir = path.dirname(oldPath);
      const newPath = path.join(parentDir, sanitizedName);

      if (!fs.existsSync(oldPath)) {
        return res.status(404).json({
          success: false,
          error: 'Cartella non trovata',
        });
      }

      if (fs.existsSync(newPath)) {
        return res.status(409).json({
          success: false,
          error: 'Una cartella con questo nome esiste già',
        });
      }

      fs.renameSync(oldPath, newPath);

      res.json({
        success: true,
        message: 'Cartella rinominata con successo',
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Elimina una cartella
   */
  deleteFolder = async (req, res) => {
    try {
      const { folderPath } = req.params;
      const fullPath = path.join(this.basePath, folderPath);

      if (!fs.existsSync(fullPath)) {
        return res.status(404).json({
          success: false,
          error: 'Cartella non trovata',
        });
      }

      // Verifica che sia una directory
      if (!fs.statSync(fullPath).isDirectory()) {
        return res.status(400).json({
          success: false,
          error: 'Il percorso non è una cartella',
        });
      }

      fs.rmSync(fullPath, { recursive: true, force: true });

      res.json({
        success: true,
        message: 'Cartella eliminata con successo',
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  // ============ VIDEO METHODS ============

  /**
   * Ottiene i video di una cartella
   */
  getVideos = async (req, res) => {
    try {
      const folder = req.query.folder || '';
      const targetPath = folder ? path.join(this.basePath, folder) : this.basePath;

      if (!fs.existsSync(targetPath)) {
        return res.json({
          success: true,
          data: {
            videos: [],
            folders: [],
            currentPath: folder,
          },
        });
      }

      const items = fs.readdirSync(targetPath);
      const videos = [];
      const subfolders = [];

      items.forEach((item) => {
        const itemPath = path.join(targetPath, item);
        const stat = fs.statSync(itemPath);

        if (stat.isDirectory()) {
          subfolders.push({
            name: item,
            path: folder ? `${folder}/${item}` : item,
          });
        } else if (stat.isFile() && this._isVideoFile(item)) {
          videos.push(this._getFileInfo(itemPath, folder));
        }
      });

      // Ordina per data di creazione (più recenti prima)
      videos.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));

      res.json({
        success: true,
        data: {
          videos,
          folders: subfolders,
          currentPath: folder,
          totalVideos: videos.length,
        },
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Upload singolo video
   */
  uploadVideo = async (req, res) => {
    try {
      if (!req.file) {
        return res.status(400).json({
          success: false,
          error: 'Nessun file caricato',
        });
      }

      // ✅ Legge da query parameter
      const folder = req.query.folder || 'default';

      const videoInfo = {
        id: uuidv4(),
        originalName: req.file.originalname,
        filename: req.file.filename,
        folder: folder,
        path: `/videos/${folder}/${req.file.filename}`,
        size: req.file.size,
        mimetype: req.file.mimetype,
        uploadedAt: new Date().toISOString(),
      };

      res.status(201).json({
        success: true,
        data: { video: videoInfo },
        message: 'Video caricato con successo',
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Upload multiplo video
   */
  uploadVideos = async (req, res) => {
    try {
      if (!req.files || req.files.length === 0) {
        return res.status(400).json({
          success: false,
          error: 'Nessun file caricato',
        });
      }

      // ✅ Legge da query parameter
      const folder = req.query.folder || 'default';

      const videos = req.files.map((file) => ({
        id: uuidv4(),
        originalName: file.originalname,
        filename: file.filename,
        folder: folder,
        path: `/videos/${folder}/${file.filename}`,
        size: file.size,
        mimetype: file.mimetype,
        uploadedAt: new Date().toISOString(),
      }));

      res.status(201).json({
        success: true,
        data: { videos },
        message: `${videos.length} video caricati con successo`,
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Ottiene info di un singolo video
   */
  getVideo = async (req, res) => {
    try {
      const { folder, filename } = req.params;
      const videoPath = path.join(this.basePath, folder, filename);

      if (!fs.existsSync(videoPath)) {
        return res.status(404).json({
          success: false,
          error: 'Video non trovato',
        });
      }

      const videoInfo = this._getFileInfo(videoPath, folder);

      res.json({
        success: true,
        data: { video: videoInfo },
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Rinomina un video
   */
  renameVideo = async (req, res) => {
    try {
      const { folder, filename } = req.params;
      const { newFilename } = req.body;

      if (!newFilename || !newFilename.trim()) {
        return res.status(400).json({
          success: false,
          error: 'Nuovo nome file richiesto',
        });
      }

      const oldPath = path.join(this.basePath, folder, filename);
      const newPath = path.join(this.basePath, folder, newFilename);

      if (!fs.existsSync(oldPath)) {
        return res.status(404).json({
          success: false,
          error: 'Video non trovato',
        });
      }

      if (fs.existsSync(newPath)) {
        return res.status(409).json({
          success: false,
          error: 'Un file con questo nome esiste già',
        });
      }

      fs.renameSync(oldPath, newPath);

      res.json({
        success: true,
        message: 'Video rinominato con successo',
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Sposta un video in un'altra cartella
   */
  moveVideo = async (req, res) => {
    try {
      const { folder, filename } = req.params;
      const { destinationFolder } = req.body;

      const sourcePath = path.join(this.basePath, folder, filename);
      const destDir = path.join(this.basePath, destinationFolder);
      const destPath = path.join(destDir, filename);

      if (!fs.existsSync(sourcePath)) {
        return res.status(404).json({
          success: false,
          error: 'Video non trovato',
        });
      }

      this._ensureDirectory(destDir);

      if (fs.existsSync(destPath)) {
        return res.status(409).json({
          success: false,
          error: 'Un file con questo nome esiste già nella destinazione',
        });
      }

      fs.renameSync(sourcePath, destPath);

      res.json({
        success: true,
        message: 'Video spostato con successo',
        data: {
          newPath: `/videos/${destinationFolder}/${filename}`,
        },
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Elimina un video
   */
  deleteVideo = async (req, res) => {
    try {
      const { folder, filename } = req.params;
      const videoPath = path.join(this.basePath, folder, filename);

      if (!fs.existsSync(videoPath)) {
        return res.status(404).json({
          success: false,
          error: 'Video non trovato',
        });
      }

      fs.unlinkSync(videoPath);

      res.json({
        success: true,
        message: 'Video eliminato con successo',
      });
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  /**
   * Stream video (per player)
   */
  streamVideo = async (req, res) => {
    try {
      const { folder, filename } = req.params;
      const videoPath = path.join(this.basePath, folder, filename);

      if (!fs.existsSync(videoPath)) {
        return res.status(404).json({
          success: false,
          error: 'Video non trovato',
        });
      }

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

      if (range) {
        const parts = range.replace(/bytes=/, '').split('-');
        const start = parseInt(parts[0], 10);
        const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
        const chunkSize = end - start + 1;

        const file = fs.createReadStream(videoPath, { start, end });
        const headers = {
          'Content-Range': `bytes ${start}-${end}/${fileSize}`,
          'Accept-Ranges': 'bytes',
          'Content-Length': chunkSize,
          'Content-Type': 'video/mp4',
        };

        res.writeHead(206, headers);
        file.pipe(res);
      } else {
        const headers = {
          'Content-Length': fileSize,
          'Content-Type': 'video/mp4',
        };

        res.writeHead(200, headers);
        fs.createReadStream(videoPath).pipe(res);
      }
    } catch (error) {
      res.status(500).json({
        success: false,
        error: error.message,
      });
    }
  };

  // ============ ERROR HANDLER MIDDLEWARE ============

  static errorHandler = (error, req, res, next) => {
    if (error.code === 'LIMIT_FILE_SIZE') {
      return res.status(413).json({
        success: false,
        error: 'File troppo grande. Dimensione massima: 500MB',
      });
    }

    if (error.code === 'LIMIT_FILE_COUNT') {
      return res.status(400).json({
        success: false,
        error: 'Troppi file. Massimo 10 file per upload',
      });
    }

    if (error.message.includes('Tipo file non supportato')) {
      return res.status(415).json({
        success: false,
        error: error.message,
      });
    }

    res.status(500).json({
      success: false,
      error: error.message || 'Errore interno del server',
    });
  };
}

module.exports = VideoController;
