const express = require('express');
const router = express.Router();
const multer = require('multer');
const sharp = require('sharp');
const path = require('path');
const fs = require('fs').promises;

// Authentication middleware
const requireAuth = (req, res, next) => {
  if (!req.session.user) {
    return res.status(401).json({
      success: false,
      message: 'Authentication required'
    });
  }
  next();
};

// Configure multer for file uploads
const storage = multer.diskStorage({
  destination: async (req, file, cb) => {
    const uploadPath = path.join(__dirname, '../public/uploads');
    try {
      await fs.mkdir(uploadPath, { recursive: true });
      cb(null, uploadPath);
    } catch (error) {
      cb(error);
    }
  },
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    const ext = path.extname(file.originalname);
    cb(null, file.fieldname + '-' + uniqueSuffix + ext);
  }
});

const upload = multer({
  storage: storage,
  limits: {
    fileSize: parseInt(process.env.MAX_FILE_SIZE) || 10 * 1024 * 1024, // 10MB
    files: 10
  },
  fileFilter: (req, file, cb) => {
    // Allow images only
    if (file.mimetype.startsWith('image/')) {
      cb(null, true);
    } else {
      cb(new Error('Only image files are allowed'), false);
    }
  }
});

// Upload single image
router.post('/upload', requireAuth, upload.single('image'), async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({
        success: false,
        message: 'No file uploaded'
      });
    }

    const originalPath = req.file.path;
    const filename = req.file.filename;
    const nameWithoutExt = path.parse(filename).name;
    
    // Create optimized versions
    const sizes = {
      thumbnail: { width: 300, height: 200 },
      medium: { width: 800, height: 600 },
      large: { width: 1200, height: 900 }
    };

    const optimizedImages = {};

    for (const [sizeName, dimensions] of Object.entries(sizes)) {
      const outputPath = path.join(
        path.dirname(originalPath),
        `${nameWithoutExt}-${sizeName}.webp`
      );

      await sharp(originalPath)
        .resize(dimensions.width, dimensions.height, {
          fit: 'inside',
          withoutEnlargement: true
        })
        .webp({ quality: 85 })
        .toFile(outputPath);

      optimizedImages[sizeName] = `/uploads/${path.basename(outputPath)}`;
    }

    // Keep original as well (converted to webp for better compression)
    const originalWebpPath = path.join(
      path.dirname(originalPath),
      `${nameWithoutExt}-original.webp`
    );

    await sharp(originalPath)
      .webp({ quality: 90 })
      .toFile(originalWebpPath);

    optimizedImages.original = `/uploads/${path.basename(originalWebpPath)}`;

    // Remove the original uploaded file
    await fs.unlink(originalPath);

    res.json({
      success: true,
      message: 'Image uploaded and optimized successfully',
      images: optimizedImages,
      metadata: {
        originalName: req.file.originalname,
        mimeType: req.file.mimetype,
        size: req.file.size
      }
    });
  } catch (error) {
    console.error('Image upload error:', error);
    
    // Clean up files on error
    if (req.file && req.file.path) {
      try {
        await fs.unlink(req.file.path);
      } catch (unlinkError) {
        console.error('Error removing file:', unlinkError);
      }
    }

    res.status(500).json({
      success: false,
      message: 'Error uploading image'
    });
  }
});

// Upload multiple images
router.post('/upload-multiple', requireAuth, upload.array('images', 10), async (req, res) => {
  try {
    if (!req.files || req.files.length === 0) {
      return res.status(400).json({
        success: false,
        message: 'No files uploaded'
      });
    }

    const uploadedImages = [];

    for (const file of req.files) {
      try {
        const originalPath = file.path;
        const filename = file.filename;
        const nameWithoutExt = path.parse(filename).name;
        
        // Create optimized versions
        const sizes = {
          thumbnail: { width: 300, height: 200 },
          medium: { width: 800, height: 600 },
          large: { width: 1200, height: 900 }
        };

        const optimizedImages = {};

        for (const [sizeName, dimensions] of Object.entries(sizes)) {
          const outputPath = path.join(
            path.dirname(originalPath),
            `${nameWithoutExt}-${sizeName}.webp`
          );

          await sharp(originalPath)
            .resize(dimensions.width, dimensions.height, {
              fit: 'inside',
              withoutEnlargement: true
            })
            .webp({ quality: 85 })
            .toFile(outputPath);

          optimizedImages[sizeName] = `/uploads/${path.basename(outputPath)}`;
        }

        // Original as webp
        const originalWebpPath = path.join(
          path.dirname(originalPath),
          `${nameWithoutExt}-original.webp`
        );

        await sharp(originalPath)
          .webp({ quality: 90 })
          .toFile(originalWebpPath);

        optimizedImages.original = `/uploads/${path.basename(originalWebpPath)}`;

        uploadedImages.push({
          originalName: file.originalname,
          images: optimizedImages,
          metadata: {
            mimeType: file.mimetype,
            size: file.size
          }
        });

        // Remove original file
        await fs.unlink(originalPath);
      } catch (fileError) {
        console.error(`Error processing file ${file.originalname}:`, fileError);
        // Clean up this file and continue with others
        try {
          await fs.unlink(file.path);
        } catch (unlinkError) {
          console.error('Error removing file:', unlinkError);
        }
      }
    }

    res.json({
      success: true,
      message: `${uploadedImages.length} images uploaded and optimized successfully`,
      images: uploadedImages
    });
  } catch (error) {
    console.error('Multiple images upload error:', error);
    
    // Clean up files on error
    if (req.files) {
      for (const file of req.files) {
        try {
          await fs.unlink(file.path);
        } catch (unlinkError) {
          console.error('Error removing file:', unlinkError);
        }
      }
    }

    res.status(500).json({
      success: false,
      message: 'Error uploading images'
    });
  }
});

// Delete image
router.delete('/:filename', requireAuth, async (req, res) => {
  try {
    const filename = req.params.filename;
    const uploadPath = path.join(__dirname, '../public/uploads');
    
    // Security check - ensure filename doesn't contain path traversal
    if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
      return res.status(400).json({
        success: false,
        message: 'Invalid filename'
      });
    }

    const filePath = path.join(uploadPath, filename);
    
    try {
      await fs.access(filePath);
      await fs.unlink(filePath);
      
      res.json({
        success: true,
        message: 'Image deleted successfully'
      });
    } catch (error) {
      if (error.code === 'ENOENT') {
        return res.status(404).json({
          success: false,
          message: 'Image not found'
        });
      }
      throw error;
    }
  } catch (error) {
    console.error('Image deletion error:', error);
    res.status(500).json({
      success: false,
      message: 'Error deleting image'
    });
  }
});

// List uploaded images with advanced filtering and search
router.get('/list', requireAuth, async (req, res) => {
  try {
    const uploadPath = path.join(__dirname, '../public/uploads');
    
    // Create uploads directory if it doesn't exist
    try {
      await fs.mkdir(uploadPath, { recursive: true });
    } catch (mkdirError) {
      // Directory might already exist, continue
    }
    
    const page = parseInt(req.query.page) || 1;
    const limit = parseInt(req.query.limit) || 24;
    const search = req.query.search?.toLowerCase() || '';
    const sortBy = req.query.sortBy || 'date'; // date, name, size
    const sortOrder = req.query.sortOrder || 'desc'; // asc, desc
    const fileType = req.query.fileType || 'all'; // all, image, video, document
    
    let files;
    try {
      files = await fs.readdir(uploadPath);
    } catch (readdirError) {
      if (readdirError.code === 'ENOENT') {
        return res.json({
          success: true,
          images: [],
          pagination: {
            current: 1,
            total: 0,
            limit,
            totalItems: 0,
            hasNext: false,
            hasPrev: false
          },
          filters: {
            search: '',
            sortBy: 'date',
            sortOrder: 'desc',
            fileType: 'all'
          }
        });
      }
      throw readdirError;
    }
    
    // Filter by file type
    let filteredFiles = files;
    if (fileType !== 'all') {
      const typePatterns = {
        image: /\.(jpg|jpeg|png|gif|webp|svg|bmp|tiff?)$/i,
        video: /\.(mp4|webm|avi|mov|mkv|wmv|flv)$/i,
        document: /\.(pdf|doc|docx|txt|rtf|odt)$/i
      };
      
      const pattern = typePatterns[fileType];
      if (pattern) {
        filteredFiles = files.filter(file => pattern.test(file));
      }
    } else {
      // Only show supported media files
      filteredFiles = files.filter(file => 
        /\.(jpg|jpeg|png|gif|webp|svg|bmp|tiff?|mp4|webm|avi|mov|mkv|pdf|doc|docx)$/i.test(file)
      );
    }

    // Apply search filter
    if (search) {
      filteredFiles = filteredFiles.filter(file => 
        file.toLowerCase().includes(search)
      );
    }

    // Get file stats and create file objects
    const filesWithStats = await Promise.all(
      filteredFiles.map(async (file) => {
        try {
          const filePath = path.join(uploadPath, file);
          const stats = await fs.stat(filePath);
          return { file, stats, filePath };
        } catch (error) {
          return null;
        }
      })
    );

    const validFiles = filesWithStats.filter(item => item !== null);

    // Sort files
    validFiles.sort((a, b) => {
      let aValue, bValue;
      
      switch (sortBy) {
        case 'name':
          aValue = a.file.toLowerCase();
          bValue = b.file.toLowerCase();
          break;
        case 'size':
          aValue = a.stats.size;
          bValue = b.stats.size;
          break;
        case 'date':
        default:
          aValue = a.stats.mtime;
          bValue = b.stats.mtime;
          break;
      }
      
      if (sortOrder === 'asc') {
        return aValue > bValue ? 1 : -1;
      } else {
        return aValue < bValue ? 1 : -1;
      }
    });

    const total = validFiles.length;
    const totalPages = Math.ceil(total / limit);
    const start = (page - 1) * limit;
    const end = start + limit;
    
    const paginatedFiles = validFiles.slice(start, end);
    
    const filesWithDetails = await Promise.all(
      paginatedFiles.map(async ({ file, stats, filePath }) => {
        try {
          const ext = path.extname(file).toLowerCase();
          let fileDetails = {
            filename: file,
            url: `/uploads/${file}`,
            size: stats.size,
            uploadedAt: stats.birthtime || stats.mtime,
            modifiedAt: stats.mtime,
            extension: ext,
            isImage: false,
            isVideo: false,
            isDocument: false
          };

          // Determine file type and get additional info
          if (/\.(jpg|jpeg|png|gif|webp|svg|bmp|tiff?)$/i.test(file)) {
            fileDetails.isImage = true;
            fileDetails.mimetype = `image/${ext.replace('.', '')}`;
            
            // Get image dimensions
            try {
              const metadata = await sharp(filePath).metadata();
              fileDetails.dimensions = {
                width: metadata.width,
                height: metadata.height
              };
              fileDetails.format = metadata.format;
            } catch (sharpError) {
              console.warn(`Could not get image metadata for ${file}`);
            }
          } else if (/\.(mp4|webm|avi|mov|mkv|wmv|flv)$/i.test(file)) {
            fileDetails.isVideo = true;
            fileDetails.mimetype = `video/${ext.replace('.', '')}`;
          } else if (/\.(pdf|doc|docx|txt|rtf|odt)$/i.test(file)) {
            fileDetails.isDocument = true;
            fileDetails.mimetype = `application/${ext.replace('.', '')}`;
          }

          // Generate thumbnail for images
          if (fileDetails.isImage && !file.includes('-thumbnail.')) {
            const thumbnailPath = path.join(uploadPath, `${path.parse(file).name}-thumbnail.webp`);
            try {
              await fs.access(thumbnailPath);
              fileDetails.thumbnail = `/uploads/${path.basename(thumbnailPath)}`;
            } catch {
              // Thumbnail doesn't exist, create it
              try {
                await sharp(filePath)
                  .resize(200, 150, {
                    fit: 'cover',
                    withoutEnlargement: false
                  })
                  .webp({ quality: 80 })
                  .toFile(thumbnailPath);
                fileDetails.thumbnail = `/uploads/${path.basename(thumbnailPath)}`;
              } catch (thumbError) {
                console.warn(`Could not create thumbnail for ${file}`);
              }
            }
          }
          
          return fileDetails;
        } catch (error) {
          console.error(`Error getting details for ${file}:`, error);
          return null;
        }
      })
    );

    const validMedia = filesWithDetails.filter(item => item !== null);

    // Calculate storage stats
    const totalSize = validFiles.reduce((sum, file) => sum + file.stats.size, 0);
    const imageCount = validMedia.filter(f => f.isImage).length;
    const videoCount = validMedia.filter(f => f.isVideo).length;
    const documentCount = validMedia.filter(f => f.isDocument).length;

    res.json({
      success: true,
      files: validMedia,
      pagination: {
        current: page,
        total: totalPages,
        limit,
        totalItems: total,
        hasNext: page < totalPages,
        hasPrev: page > 1
      },
      filters: {
        search,
        sortBy,
        sortOrder,
        fileType
      },
      stats: {
        totalFiles: total,
        totalSize,
        imageCount,
        videoCount,
        documentCount,
        formattedSize: formatFileSize(totalSize)
      }
    });
  } catch (error) {
    console.error('List media error:', error);
    res.status(500).json({
      success: false,
      message: 'Error listing media files'
    });
  }
});

// Create folder structure
router.post('/folder', requireAuth, async (req, res) => {
  try {
    const { folderName } = req.body;
    
    if (!folderName || !folderName.trim()) {
      return res.status(400).json({
        success: false,
        message: 'Folder name is required'
      });
    }

    // Sanitize folder name
    const sanitizedName = folderName.trim().replace(/[^a-zA-Z0-9-_]/g, '-');
    const folderPath = path.join(__dirname, '../public/uploads', sanitizedName);
    
    try {
      await fs.mkdir(folderPath, { recursive: true });
      
      res.json({
        success: true,
        message: 'Folder created successfully',
        folderName: sanitizedName,
        folderPath: `/uploads/${sanitizedName}`
      });
    } catch (error) {
      if (error.code === 'EEXIST') {
        return res.status(400).json({
          success: false,
          message: 'Folder already exists'
        });
      }
      throw error;
    }
  } catch (error) {
    console.error('Create folder error:', error);
    res.status(500).json({
      success: false,
      message: 'Error creating folder'
    });
  }
});

// Get media file info
router.get('/info/:filename', requireAuth, async (req, res) => {
  try {
    const filename = req.params.filename;
    
    // Security check
    if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
      return res.status(400).json({
        success: false,
        message: 'Invalid filename'
      });
    }

    const filePath = path.join(__dirname, '../public/uploads', filename);
    
    try {
      const stats = await fs.stat(filePath);
      const ext = path.extname(filename).toLowerCase();
      
      let fileInfo = {
        filename,
        url: `/uploads/${filename}`,
        size: stats.size,
        formattedSize: formatFileSize(stats.size),
        uploadedAt: stats.birthtime || stats.mtime,
        modifiedAt: stats.mtime,
        extension: ext,
        mimetype: getMimeType(ext)
      };

      // Get additional info for images
      if (/\.(jpg|jpeg|png|gif|webp|svg|bmp|tiff?)$/i.test(filename)) {
        try {
          const metadata = await sharp(filePath).metadata();
          fileInfo.dimensions = {
            width: metadata.width,
            height: metadata.height
          };
          fileInfo.format = metadata.format;
          fileInfo.hasAlpha = metadata.hasAlpha;
          fileInfo.density = metadata.density;
        } catch (sharpError) {
          console.warn(`Could not get image metadata for ${filename}`);
        }
      }

      res.json({
        success: true,
        fileInfo
      });
    } catch (error) {
      if (error.code === 'ENOENT') {
        return res.status(404).json({
          success: false,
          message: 'File not found'
        });
      }
      throw error;
    }
  } catch (error) {
    console.error('Get file info error:', error);
    res.status(500).json({
      success: false,
      message: 'Error getting file information'
    });
  }
});

// Resize image
router.post('/resize/:filename', requireAuth, async (req, res) => {
  try {
    const filename = req.params.filename;
    const { width, height, quality = 85 } = req.body;
    
    if (!width && !height) {
      return res.status(400).json({
        success: false,
        message: 'Width or height must be specified'
      });
    }

    // Security check
    if (filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
      return res.status(400).json({
        success: false,
        message: 'Invalid filename'
      });
    }

    const originalPath = path.join(__dirname, '../public/uploads', filename);
    const nameWithoutExt = path.parse(filename).name;
    const resizedPath = path.join(
      path.dirname(originalPath),
      `${nameWithoutExt}-${width || 'auto'}x${height || 'auto'}.webp`
    );

    try {
      let sharpInstance = sharp(originalPath);
      
      if (width && height) {
        sharpInstance = sharpInstance.resize(parseInt(width), parseInt(height), {
          fit: 'cover'
        });
      } else if (width) {
        sharpInstance = sharpInstance.resize(parseInt(width));
      } else {
        sharpInstance = sharpInstance.resize(null, parseInt(height));
      }

      await sharpInstance
        .webp({ quality: parseInt(quality) })
        .toFile(resizedPath);

      res.json({
        success: true,
        message: 'Image resized successfully',
        originalFile: filename,
        resizedFile: path.basename(resizedPath),
        resizedUrl: `/uploads/${path.basename(resizedPath)}`
      });
    } catch (error) {
      if (error.code === 'ENOENT') {
        return res.status(404).json({
          success: false,
          message: 'Original file not found'
        });
      }
      throw error;
    }
  } catch (error) {
    console.error('Resize image error:', error);
    res.status(500).json({
      success: false,
      message: 'Error resizing image'
    });
  }
});

// Utility functions
function formatFileSize(bytes) {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

function getMimeType(ext) {
  const mimeTypes = {
    '.jpg': 'image/jpeg',
    '.jpeg': 'image/jpeg',
    '.png': 'image/png',
    '.gif': 'image/gif',
    '.webp': 'image/webp',
    '.svg': 'image/svg+xml',
    '.bmp': 'image/bmp',
    '.tiff': 'image/tiff',
    '.tif': 'image/tiff',
    '.mp4': 'video/mp4',
    '.webm': 'video/webm',
    '.avi': 'video/x-msvideo',
    '.mov': 'video/quicktime',
    '.mkv': 'video/x-matroska',
    '.pdf': 'application/pdf',
    '.doc': 'application/msword',
    '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
  };
  
  return mimeTypes[ext.toLowerCase()] || 'application/octet-stream';
}

module.exports = router;