import { Request, Response } from 'express';
import path from 'node:path';
import fs from 'node:fs';

import db, { handlePrismaError } from '../../../../handlers/db.js'; // Database
import log from '../../../../handlers/log.js';
import __path from '../../../../handlers/path.js';
import { schema_get, schema_post, schema_del } from './image_schema.js';
import { UploadedFile } from 'express-fileupload';

// MARK: GET image
async function get(req: Request, res: Response) {
	const { error, value } = schema_get.validate(req.query);
	if (error) {
		log.api?.debug('GET image Error:', req.query, value, error.details[0].message);
		res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
	} else {
		log.api?.debug('GET image Success:', req.query, value);
		const img_path = path.join(__path, 'images', `${value.id}.png`);
		const img_default_path = path.join(__path, 'images', 'default.png');

		const img_existing = fs.existsSync(img_path);
		const img_default_existing = fs.existsSync(img_default_path);

		if (value.check) {
			res.status(200).json(img_existing);
			return;
		}

		if (!img_default_existing) {
			log.api?.warn('Default image not found! Please make sure the following path contains an png file:', img_default_path);
		}

		await db.products
			.findUnique({
				where: {
					id: value.id
				}
			})
			.then((result) => {
				if (result) {
					// Serve stored or default image
					log.api?.debug('Image exists:', img_existing);
					img_existing ? res.sendFile(img_path) : res.sendFile(img_default_path);
				} else {
					// Product does not exist
					log.api?.debug('Product does not exist, using default image ');
					res.sendFile(img_default_path);
				}
			})
			.catch((err) => {
				handlePrismaError(err, res, 'GET image');
			});
	}
}

// MARK: CREATE/UPDATE image (upload)
async function post(req: Request, res: Response) {
	const { error, value } = schema_post.validate(req.query);
	if (error) {
		log.api?.debug('POST image Error:', req.query, value, error.details[0].message);
		res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
	} else {
		// Check if multipart has image with file
		if (!req.files || !req.files.image) {
			res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'Missing image' });
			return;
		}

		const upload_file = req.files.image as UploadedFile;
		const upload_path = path.join(__path, 'images', `${value.id}.png`);
		const allowedMimeTypes = ['image/png'];

		// Check if mimetype is allowed
		if (!allowedMimeTypes.includes(upload_file.mimetype)) {
			res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: 'Only image/png is allowed' });
			return;
		}
		// Check if product exists
		const result = await db.products.findUnique({
			where: {
				id: value.id
			}
		});

		if (!result) {
			res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Could not find specified product' });
			return;
		}

		// Write file
		upload_file.mv(upload_path, (err) => {
			if (err) {
				res.status(500).json({ status: 'ERROR', errorcode: 'IO_ERROR', message: 'Could not write image to disk' });
				return;
			}
			log.api?.debug('File uploaded to:', upload_path);
			res.status(200).json({ status: 'CREATED', message: 'Successfully uploaded image', id: result.id });
		});
	}
}

// MARK: DELETE image
async function del(req: Request, res: Response) {
	const { error, value } = schema_del.validate(req.query);
	if (error) {
		log.api?.debug('DEL image Error:', req.query, value, error.details[0].message);
		res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
	} else {
		log.api?.debug('DEL image Success:', req.query, value);
		const del_path = path.join(__path, 'images', `${value.id}.png`);
		await db.products
			.findUnique({
				where: {
					id: value.id
				}
			})
			.then((result) => {
				if (result) {
					if (!fs.existsSync(del_path)) {
						res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Product exists but no image found' });
						return;
					}
					fs.unlink(del_path, (err) => {
						if (err) {
							res.status(500).json({ status: 'ERROR', errorcode: 'IO_ERROR', message: 'Could not delete image' });
							return;
						}
						res.status(200).json({ status: 'DELETED', message: 'Successfully deleted image', id: result.id });
						log.api?.debug('File removed from:', del_path);
					});
				} else {
					res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Could not find specified product (image)' });
				}
			})
			.catch((err) => {
				handlePrismaError(err, res, 'DEL products');
			});
	}
}

export default { get, post, del };
