import { Request, Response } from 'express';
import db, { handlePrismaError } from '../../../../handlers/db.js'; // Database
import log from '../../../../handlers/log.js';
import { parseDynamicSortBy } from '../../../../helpers/prisma_helpers.js';
import { schema_get, schema_post, schema_patch, schema_del } from './products_schema.js';

// MARK: GET products
async function get(req: Request, res: Response) {
	const { error, value } = schema_get.validate(req.query);
	if (error) {
		log.api?.debug('GET products 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 products Success:', req.query, value);

		if (value.search !== undefined || value.id !== undefined || value.gtin !== undefined) {
			// if search or get by id/gtin
			await db
				.$transaction([
					// Same query for count and findMany
					db.products.count({
						where: {
							OR: [{ id: value.id }, { gtin: value.gtin }, { name: { search: value.search } }]
						},
						orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
						skip: value.skip,
						take: value.take
					}),
					db.products.findMany({
						where: {
							OR: [{ id: value.id }, { gtin: value.gtin }, { name: { search: value.search } }]
						},
						orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
						skip: value.skip,
						take: value.take
					})
				])
				.then(([count, result]) => {
					if (result.length !== 0) {
						res.status(200).json({ count, result });
					} else {
						res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Could not find specified product' });
					}
				})
				.catch((err) => {
					handlePrismaError(err, res, 'GET products');
				});
		} else {
			// get all
			await db
				.$transaction([
					// Same query for count and findMany
					db.products.count({
						orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
						skip: value.skip,
						take: value.take
					}),
					db.products.findMany({
						orderBy: parseDynamicSortBy(value.sort.toString(), value.order.toString()),
						skip: value.skip,
						take: value.take
					})
				])
				.then(([count, result]) => {
					if (result.length !== 0) {
						res.status(200).json({ count, result });
					} else {
						res.status(404).json({ status: 'ERROR', errorcode: 'NOT_FOUND', message: 'Could not find specified product' });
					}
				})
				.catch((err) => {
					handlePrismaError(err, res, 'GET products');
				});
		}
	}
}

// MARK: CREATE products
async function post(req: Request, res: Response) {
	const { error, value } = schema_post.validate(req.body);
	if (error) {
		log.api?.debug('POST products Error:', req.body, value, error.details[0].message);
		res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
	} else {
		log.api?.debug('POST products Success:', req.body, value);
		await db.products
			.create({
				data: {
					gtin: value.gtin,
					name: value.name,
					price: value.price,
					stock: value.stock,
					visible: value.visible
				},
				select: {
					id: true
				}
			})
			.then((result) => {
				res.status(201).json({ status: 'CREATED', message: 'Successfully created product', id: result.id });
			})
			.catch((err) => {
				handlePrismaError(err, res, 'POST products');
			});
	}
}

// MARK: UPDATE products
async function patch(req: Request, res: Response) {
	const { error, value } = schema_patch.validate(req.body);
	if (error) {
		log.api?.debug('PATCH products Error:', req.body, value, error.details[0].message);
		res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
	} else {
		log.api?.debug('PATCH products Success:', req.body, value);
		await db.products
			.update({
				where: {
					id: value.id
				},
				data: {
					gtin: value.gtin,
					name: value.name,
					price: value.price,
					stock: value.stock,
					visible: value.visible
				},
				select: {
					id: true
				}
			})
			.then((result) => {
				res.status(200).json({ status: 'UPDATED', message: 'Successfully updated product', id: result.id });
			})
			.catch((err) => {
				handlePrismaError(err, res, 'PATCH products');
			});
	}
}

// MARK: DELETE products
async function del(req: Request, res: Response) {
	const { error, value } = schema_del.validate(req.body);
	if (error) {
		log.api?.debug('DEL products Error:', req.body, value, error.details[0].message);
		res.status(400).json({ status: 'ERROR', errorcode: 'VALIDATION_ERROR', message: error.details[0].message });
	} else {
		log.api?.debug('DEL products Success:', req.body, value);
		await db.products
			.delete({
				where: {
					id: value.id
				}
			})
			.then((result) => {
				res.status(200).json({ status: 'DELETED', message: 'Successfully deleted product', id: result.id });
			}).catch((err) => {
				handlePrismaError(err, res, 'DEL products');
			});
	}
}

export default { get, post, patch, del };
