import { Router, Request, Response, NextFunction } from 'express';
import { PrismaClient } from '@prisma/client';
import multer from 'multer';
import path from 'path';
import fs from 'fs';
import { config } from '../config/config';

const router = Router();
const prisma = new PrismaClient();

// Utility function to get correct uploads directory path
const getUploadsDir = (subPath?: string): string => {
  const baseDir = process.env.NODE_ENV === 'production' 
    ? path.join(process.cwd(), 'uploads') 
    : path.join(process.cwd(), '../../uploads');
  
  return subPath ? path.join(baseDir, subPath) : baseDir;
};

// Configure multer for file uploads
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const recipeNumber = req.body.recipeNumber || req.params.recipeNumber;
    if (!recipeNumber) {
      return cb(new Error('Recipe number is required'), '');
    }
    
    const uploadDir = getUploadsDir(recipeNumber);
    
    // Create directory if it doesn't exist
    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }
    
    cb(null, uploadDir);
  },
  filename: (req, file, cb) => {
    const recipeNumber = req.body.recipeNumber || req.params.recipeNumber;
    if (!recipeNumber) {
      return cb(new Error('Recipe number is required'), '');
    }
    
    // Get existing files count to determine next index
    const uploadDir = getUploadsDir(recipeNumber);
    const existingFiles = fs.existsSync(uploadDir) 
      ? fs.readdirSync(uploadDir).filter(f => f.match(new RegExp(`^${recipeNumber}_\\d+\\.jpg$`)))
      : [];
    
    const nextIndex = existingFiles.length;
    const filename = `${recipeNumber}_${nextIndex}.jpg`;
    
    cb(null, filename);
  }
});

const upload = multer({
  storage,
  limits: {
    fileSize: config.upload.maxFileSize, // 5MB
  },
  fileFilter: (req, file, cb) => {
    const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
    if (allowedTypes.includes(file.mimetype)) {
      cb(null, true);
    } else {
      cb(new Error('Invalid file type. Only JPEG, PNG and WebP are allowed.'));
    }
  },
});

// Upload images for a recipe
router.post('/upload/:recipeId', upload.array('images', 10), async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { recipeId } = req.params;
    const files = req.files as Express.Multer.File[];
    
    if (!recipeId) {
      return res.status(400).json({
        success: false,
        message: 'Recipe ID is required',
      });
    }
    
    if (!files || files.length === 0) {
      return res.status(400).json({
        success: false,
        message: 'No files uploaded',
      });
    }
    
    // Get recipe to validate it exists and get recipe number
    const recipe = await prisma.recipe.findUnique({
      where: { id: parseInt(recipeId) }
    });
    
    if (!recipe) {
      return res.status(404).json({
        success: false,
        message: 'Recipe not found',
      });
    }
    
    // Create database entries for uploaded images
    const imagePromises = files.map(file => {
      const relativePath = `uploads/${recipe.recipeNumber}/${file.filename}`;
      return prisma.recipeImage.create({
        data: {
          recipeId: parseInt(recipeId),
          filePath: relativePath,
        }
      });
    });
    
    const images = await Promise.all(imagePromises);
    
    return res.status(201).json({
      success: true,
      data: images,
      message: `${files.length} images uploaded successfully`,
    });
  } catch (error) {
    // Clean up uploaded files if database operation fails
    if (req.files) {
      const files = req.files as Express.Multer.File[];
      files.forEach(file => {
        if (fs.existsSync(file.path)) {
          fs.unlinkSync(file.path);
        }
      });
    }
    next(error);
  }
});

// Delete an image
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { id } = req.params;
    
    if (!id) {
      return res.status(400).json({
        success: false,
        message: 'Image ID is required',
      });
    }
    
    const image = await prisma.recipeImage.findUnique({
      where: { id: parseInt(id) }
    });
    
    if (!image) {
      return res.status(404).json({
        success: false,
        message: 'Image not found',
      });
    }
    
    // Delete file from filesystem
    const fullPath = path.join(process.cwd(), '../..', image.filePath);
    if (fs.existsSync(fullPath)) {
      fs.unlinkSync(fullPath);
    }
    
    // Delete from database
    await prisma.recipeImage.delete({
      where: { id: parseInt(id) }
    });
    
    return res.json({
      success: true,
      message: 'Image deleted successfully',
    });
  } catch (error) {
    next(error);
  }
});

// Get all images for a recipe by recipe ID
router.get('/recipe/:recipeId', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { recipeId } = req.params;
    
    if (!recipeId) {
      return res.status(400).json({
        success: false,
        message: 'Recipe ID is required',
      });
    }
    
    const images = await prisma.recipeImage.findMany({
      where: { recipeId: parseInt(recipeId) },
      orderBy: { id: 'asc' }
    });

    return res.json({
      success: true,
      data: images,
    });
  } catch (error) {
    next(error);
  }
});

// Serve image file
router.get('/serve/:imagePath(*)', (req: Request, res: Response, next: NextFunction) => {
  try {
    const imagePath = req.params.imagePath;
    
    if (!imagePath) {
      return res.status(400).json({
        success: false,
        message: 'Image path is required',
      });
    }
    
    // Remove leading 'uploads/' if present to avoid duplication
    const cleanPath = imagePath.replace(/^uploads\//, '');
    const fullPath = path.join(getUploadsDir(), cleanPath);
    
    console.log(`Serving image: ${imagePath} -> ${fullPath}`);
    
    if (!fs.existsSync(fullPath)) {
      console.log(`Image not found: ${fullPath}`);
      return res.status(404).json({
        success: false,
        message: 'Image not found',
        requestedPath: imagePath,
        resolvedPath: fullPath
      });
    }

    // Set CORS headers for images - support multiple origins including local network
    const allowedOrigins = ['http://localhost:5173', 'http://localhost:3000'];
    const origin = req.headers.origin;
    
    // Check if CORS_ORIGIN is set to "*" for local network access
    const corsOrigin = process.env.CORS_ORIGIN === '*' 
      ? (origin || '*')
      : (origin && allowedOrigins.includes(origin)) ? origin : 'http://localhost:3000';
    
    res.set({
      'Access-Control-Allow-Origin': corsOrigin,
      'Access-Control-Allow-Credentials': 'true',
      'Cache-Control': 'public, max-age=31536000', // Cache for 1 year
    });

    return res.sendFile(path.resolve(fullPath));
  } catch (error) {
    console.error('Error serving image:', error);
    next(error);
  }
});

// Get image metadata
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { id } = req.params;
    
    if (!id) {
      return res.status(400).json({
        success: false,
        message: 'Image ID is required',
      });
    }
    
    const image = await prisma.recipeImage.findUnique({
      where: { id: parseInt(id) }
    });

    if (!image) {
      return res.status(404).json({
        success: false,
        message: 'Image not found',
      });
    }

    return res.json({
      success: true,
      data: image,
    });
  } catch (error) {
    next(error);
  }
});

export default router;