import { Router, Response } from 'express';
import multer from 'multer';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';
import sharp from 'sharp';
import fs from 'fs/promises';
import { Media } from '../models/index.js';
import { authenticate, requireRole, AuthRequest } from '../middleware/auth.js';
import { config } from '../config/index.js';

const router = Router();

// Configure multer
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const uploadPath = path.join(process.cwd(), config.uploadDir);
    fs.mkdir(uploadPath, { recursive: true })
      .then(() => cb(null, uploadPath))
      .catch((err) => cb(err as Error, uploadPath));
  },
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname);
    const filename = `${uuidv4()}${ext}`;
    cb(null, filename);
  },
});

const fileFilter = (req: Express.Request, file: Express.Multer.File, cb: multer.FileFilterCallback) => {
  const allowedTypes = [
    'image/jpeg',
    'image/png',
    'image/gif',
    'image/webp',
    'image/svg+xml',
    'image/avif',
    'image/heic',
    'image/heif',
    'image/tiff',
    'image/bmp',
    'application/pdf',
    'video/mp4',
    'video/webm',
  ];

  if (allowedTypes.includes(file.mimetype)) {
    cb(null, true);
  } else {
    cb(new Error('Invalid file type'));
  }
};

const upload = multer({
  storage,
  fileFilter,
  limits: {
    fileSize: config.maxFileSize,
  },
});

// GET /api/media - Get all media
router.get('/', authenticate, async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const { folder, type, page = 1, limit = 20 } = req.query;

    const query: Record<string, unknown> = {};
    if (folder) query.folder = folder;
    if (type) {
      if (type === 'image') query.mimetype = { $regex: /^image/ };
      if (type === 'video') query.mimetype = { $regex: /^video/ };
      if (type === 'document') query.mimetype = { $regex: /pdf/ };
    }

    const media = await Media.find(query)
      .populate('uploadedBy', 'name')
      .sort({ createdAt: -1 })
      .skip((Number(page) - 1) * Number(limit))
      .limit(Number(limit));

    const total = await Media.countDocuments(query);

    res.json({
      media,
      pagination: {
        page: Number(page),
        limit: Number(limit),
        total,
        pages: Math.ceil(total / Number(limit)),
      },
    });
  } catch (error) {
    res.status(500).json({ error: 'Server error' });
  }
});

// POST /api/media - Upload file
router.post(
  '/',
  authenticate,
  requireRole('admin', 'editor', 'author'),
  (req, res, next) => {
    upload.single('file')(req, res, (err) => {
      if (err) {
        console.error('Multer error:', err);
        res.status(400).json({ error: err.message || 'Upload failed' });
        return;
      }
      next();
    });
  },
  async (req: AuthRequest, res: Response): Promise<void> => {
    try {
      if (!req.file) {
        res.status(400).json({ error: 'No file uploaded' });
        return;
      }

      const { folder = 'general', alt, caption } = req.body;

      // Get image dimensions if it's an image
      let dimensions: { width: number; height: number } | undefined;
      if (req.file.mimetype.startsWith('image/') && !req.file.mimetype.includes('svg')) {
        try {
          const metadata = await sharp(req.file.path).metadata();
          if (metadata.width && metadata.height) {
            dimensions = {
              width: metadata.width,
              height: metadata.height,
            };
          }
        } catch (e) {
          // Ignore errors for non-processable images
        }
      }

      const media = new Media({
        filename: req.file.filename,
        originalName: req.file.originalname,
        mimetype: req.file.mimetype,
        size: req.file.size,
        path: req.file.path,
        url: `/uploads/${req.file.filename}`,
        alt,
        caption,
        uploadedBy: req.user!._id,
        folder,
        dimensions,
      });

      await media.save();
      res.status(201).json(media);
    } catch (error) {
      console.error('Upload error:', error);
      res.status(500).json({ error: 'Server error' });
    }
  }
);

// PUT /api/media/:id - Update media metadata
router.put(
  '/:id',
  authenticate,
  requireRole('admin', 'editor'),
  async (req: AuthRequest, res: Response): Promise<void> => {
    try {
      const { alt, caption, folder } = req.body;

      const media = await Media.findByIdAndUpdate(
        req.params.id,
        { $set: { alt, caption, folder } },
        { returnDocument: 'after' }
      );

      if (!media) {
        res.status(404).json({ error: 'Media not found' });
        return;
      }

      res.json(media);
    } catch (error) {
      res.status(500).json({ error: 'Server error' });
    }
  }
);

// DELETE /api/media/:id - Delete media
router.delete(
  '/:id',
  authenticate,
  requireRole('admin', 'editor'),
  async (req: AuthRequest, res: Response): Promise<void> => {
    try {
      const media = await Media.findById(req.params.id);

      if (!media) {
        res.status(404).json({ error: 'Media not found' });
        return;
      }

      // Delete file from disk
      try {
        await fs.unlink(media.path);
      } catch (e) {
        console.error('Error deleting file:', e);
      }

      await Media.findByIdAndDelete(req.params.id);

      res.json({ message: 'Media deleted successfully' });
    } catch (error) {
      res.status(500).json({ error: 'Server error' });
    }
  }
);

export default router;
