import multer from "multer";
import path from "path";
import fs from "fs";
import type { Request, Response, NextFunction } from "express";

interface FieldConfig {
    name: string;      // form field name, e.g. "logo" or "authorizedSign"
    folder: string;     // destination folder for this field's files
    prefix?: string;    // filename prefix, defaults to field name
    maxCount?: number;  // defaults to 1
}

/**
 * Multi-field upload middleware. Supports multiple named file fields in a
 * single multipart request, each saved to its own folder with its own
 * filename prefix (e.g. logo -> uploads/logos, authorizedSign -> uploads/signatures).
 */
export const createFieldsUploadMiddleware = (fields: FieldConfig[]) => {
    // Ensure every destination folder exists up front
    fields.forEach(({ folder }) => {
        const dir = path.join(process.cwd(), folder);
        if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true });
        }
    });

    const folderByField = new Map(fields.map((f) => [f.name, f.folder]));
    const prefixByField = new Map(fields.map((f) => [f.name, f.prefix ?? f.name]));

    const storage = multer.diskStorage({
        destination(req, file, cb) {
            const folder = folderByField.get(file.fieldname);
            if (!folder) {
                return cb(new Error(`Unexpected field: ${file.fieldname}`), "");
            }
            cb(null, path.join(process.cwd(), folder));
        },
        filename(req, file, cb) {
            const prefix = prefixByField.get(file.fieldname) ?? "file";
            const unique = Date.now() + "-" + Math.round(Math.random() * 1000000);
            cb(null, prefix + "-" + unique + path.extname(file.originalname));
        },
    });

    const upload = multer({
        storage,
        limits: {
            fileSize: 5 * 1024 * 1024, // 5MB limit
        },
        fileFilter(req, file, cb) {
            const allowed = /jpeg|jpg|png|gif/;
            const mime = allowed.test(file.mimetype);
            const ext = allowed.test(path.extname(file.originalname).toLowerCase());

            if (mime && ext) {
                cb(null, true);
            } else {
                cb(new Error("Only image files are allowed(.jpeg, .jpg, .png)."));
            }
        },
    }).fields(
        fields.map(({ name, maxCount }) => ({
            name,
            maxCount: maxCount ?? 1,
        }))
    );

    return (req: Request, res: Response, next: NextFunction) => {
        upload(req, res, (err) => {
            if (err) {
                return res.status(400).json({
                    success: false,
                    message: err.message,
                });
            }
            next();
        });
    };
};

// Kept for any other controller still using a single-field upload.
export const createUploadMiddleware = (folderPath: string, fieldName: string, prefix: string = "file") => {
    const uploadDir = path.join(process.cwd(), folderPath);

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

    const storage = multer.diskStorage({
        destination(req, file, cb) {
            cb(null, uploadDir);
        },
        filename(req, file, cb) {
            const unique = Date.now() + "-" + Math.round(Math.random() * 1000000);
            cb(null, prefix + "-" + unique + path.extname(file.originalname));
        },
    });

    const upload = multer({
        storage,
        limits: {
            fileSize: 5 * 1024 * 1024,
        },
        fileFilter(req, file, cb) {
            const allowed = /jpeg|jpg|png|gif/;
            const mime = allowed.test(file.mimetype);
            const ext = allowed.test(path.extname(file.originalname).toLowerCase());

            if (mime && ext) {
                cb(null, true);
            } else {
                cb(new Error("Only image files are allowed(.jpeg, .jpg, .png)."));
            }
        },
    }).single(fieldName);

    return (req: Request, res: Response, next: NextFunction) => {
        upload(req, res, (err) => {
            if (err) {
                return res.status(400).json({
                    success: false,
                    message: err.message,
                });
            }
            next();
        });
    };
};

/**
 * Memory-storage multer middleware for a single Excel (.xlsx) file.
 * The parsed buffer is available at req.file.buffer.
 */
export const createExcelUploadMiddleware = (fieldName: string = "file") => {
    const upload = multer({
        storage: multer.memoryStorage(),
        limits: { fileSize: 5 * 1024 * 1024 },
        fileFilter(_req, file, cb) {
            const ext = path.extname(file.originalname).toLowerCase();
            if (ext === ".xlsx") {
                cb(null, true);
            } else {
                cb(new Error("Only Excel (.xlsx) files are allowed."));
            }
        },
    }).single(fieldName);

    return (req: Request, res: Response, next: NextFunction) => {
        upload(req, res, (err) => {
            if (err) {
                return res.status(400).json({ message: err.message });
            }
            next();
        });
    };
};

//  Middleware for handling multiple image uploads
export const createMultipleUploadMiddleware = (
    folderPath: string,
    fieldName: string = "images",
    maxCount: number = 10,
    maxFileSizeMb: number = 5,
    prefix: string = "invoice"
) => {
    const uploadDir = path.join(process.cwd(), folderPath);

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

    const storage = multer.diskStorage({
        destination(req, file, cb) {
            if (!fs.existsSync(uploadDir)) {
                fs.mkdirSync(uploadDir, { recursive: true });
            }
            cb(null, uploadDir);
        },
        filename(req, file, cb) {
            const unique = Date.now() + "-" + Math.round(Math.random() * 1000000);
            cb(null, `${prefix}-${unique}${path.extname(file.originalname)}`);
        },
    });

    const upload = multer({
        storage,
        limits: {
            fileSize: maxFileSizeMb * 1024 * 1024,
            files: maxCount,
        },
        fileFilter(req, file, cb) {
            const allowed = /jpeg|jpg|png/;
            const mime = allowed.test(file.mimetype);
            const ext = allowed.test(path.extname(file.originalname).toLowerCase());

            if (mime && ext) {
                cb(null, true);
            } else {
                cb(new Error("Only image files are allowed (.jpeg, .jpg, .png)."));
            }
        },
    }).array(fieldName, maxCount);

    return (req: Request, res: Response, next: NextFunction) => {
        if (!fs.existsSync(uploadDir)) {
            fs.mkdirSync(uploadDir, { recursive: true });
        }
        upload(req, res, (err) => {
            if (err) {
                return res.status(400).json({
                    success: false,
                    message: err.message,
                });
            }
            next();
        });
    };
};
