import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js";
import { serverSettings } from "../../../server/controller/settings/getSettings.js";
import { query } from "../../../sqlServer/prodSqlServer.js";
import { machineCheck } from "../../../sqlServer/querys/ocp/machineId.js";
import { mmQuery } from "../../../sqlServer/querys/ocp/mainMaterial.js";

export const isMainMatStaged = async (lot: any) => {
	const set = serverSettings.length === 0 ? [] : serverSettings;
	// make staged false by deefault and error logged if theres an issue
	let isStaged = { message: "Material is staged", success: true };

	const { data, error } = (await tryCatch(
		query(
			machineCheck.replace("where Active = 1 and [Location] = [loc]", ""),
			"check machine needs mm",
		),
	)) as any;

	const machine = data.data.filter(
		(m: any) => m.HumanReadableId === lot.machineID,
	);
	// we have a check on ksc side to ignore the tetra machine for now as its not updating in 2.0
	if (!machine[0].StagingMainMaterialMandatory) {
		createLog(
			"info",
			"mainMaterial",
			"ocp",
			`The machine dose not require mm to print and book in.`,
		);
		return {
			message: "Machine dose not require material to be staged",
			success: true,
		};
	}

	// strangly the lot is not always sending over in slc so adding this in for now to see what line is cauing this issue
	if (!lot) {
		createLog("info", "mainMaterial", "ocp", "No lot was passed correctly.");
		return isStaged;
	}

	if (typeof lot !== "object" || lot === null || Array.isArray(lot)) {
		createLog(
			"info",
			"mainMaterial",
			"ocp",
			`The lot sent over is not an object: ${JSON.stringify(lot)}`,
		);
		return isStaged;
	}

	const updateQuery = mmQuery.replaceAll("[lotNumber]", lot.lot);

	try {
		const r: any = await query(updateQuery, "Main Material Check");

		const res: any = r.data;

		// if (res[0].Staged >= 1) {
		//     isStaged = true;
		// }

		type CheckConditionArgs = {
			results: any[];
			filterFn: (n: any) => boolean;
			failCondition: (n: any) => boolean;
			failMessage: string;
			successMessage: string;
			lot: { lot: string | number };
		};

		const checkCondition = ({
			results,
			filterFn,
			failCondition,
			failMessage,
			successMessage,
			lot,
		}: CheckConditionArgs): { message: string; success: boolean } => {
			const subset = results.filter(filterFn);

			if (subset.some(failCondition)) {
				const failing = subset.filter(failCondition);
				createLog(
					"info",
					"mainMaterial",
					"ocp",
					`lot: ${lot.lot}, is missing: ${failing
						.map(
							(o: any) =>
								`${o.MaterialHumanReadableId} - ${o.MaterialDescription}`,
						)
						.join(",\n ")} ${failMessage}`,
				);
				return {
					message: `lot: ${lot.lot}, is missing: ${failing
						.map(
							(o: any) =>
								`${o.MaterialHumanReadableId} - ${o.MaterialDescription}`,
						)
						.join(",\n ")} ${failMessage}`,
					success: false,
				};
			} else {
				createLog(
					"info",
					"mainMaterial",
					"ocp",
					`lot: ${lot.lot}, ${JSON.stringify(results)}`,
				);
				return { message: successMessage, success: true };
			}
		};

		createLog("info", "mainMaterial", "ocp", `Maint material query ran.`);

		const mainMaterial = res.find((n: any) => n.IsMainMaterial);
		if (mainMaterial?.Staged === 1) {
			createLog(
				"info",
				"mainMaterial",
				"ocp",
				`Main material: ${mainMaterial.MaterialHumanReadableId} - ${mainMaterial.MaterialDescription}: is staged for ${lot.lot}`,
			);
			return {
				message: `Main material: ${mainMaterial.MaterialHumanReadableId} - ${mainMaterial.MaterialDescription}: is staged for ${lot.lot}`,
				success: true,
			};
		}
		if (mainMaterial?.noMMShortage === "noMM") {
			createLog(
				"info",
				"mainMaterial",
				"ocp",
				`Main material: ${mainMaterial.MaterialHumanReadableId} - ${mainMaterial.MaterialDescription}: is not staged for ${lot.lot}`,
			);
			return {
				message: `Main material: ${mainMaterial.MaterialHumanReadableId} - ${mainMaterial.MaterialDescription}: is not staged for ${lot.lot}`,
				success: false,
			};
		}

		// we need to filter the color stuff and then look for includes instead of a standard name. this way we can capture a everything and not a single type
		// for manual consume color if active to check colors
		const checkColorSetting = set.filter((n) => n.name === "checkColor");

		// 2. Auto color
		if (checkColorSetting[0].value === "1") {
			// auto check
			// 2. Auto color
			const autoColor = checkCondition({
				results: res,
				lot,
				filterFn: (n) =>
					n.isManual &&
					!("noPKGAutoShortage" in n) &&
					!("noPKGManualShortage" in n), // pool = non-main, auto
				failCondition: (n) => n.autoConsumeCheck === "autoConsumeNOK", // column = autoConsumeCheck
				failMessage: "for autoconsume",
				successMessage: "auto color is good",
			});
			if (!autoColor.success) return autoColor;
			createLog(
				"info",
				"mainMaterial",
				"ocp",
				`Auto Color: ${JSON.stringify(autoColor)}`,
			);

			// 3. Manual color
			const manualColor = checkCondition({
				results: res,
				lot,
				filterFn: (n) =>
					!n.IsMainMaterial &&
					n.isManual &&
					!("noPKGAutoShortage" in n) &&
					!("noPKGManualShortage" in n), // pool = non-main, manual
				failCondition: (n) => n.noManualShortage === "noOK", // column = noManualShortage
				failMessage: "for manual material",
				successMessage: "manual color is good",
			});
			if (!manualColor.success) return manualColor;
			createLog(
				"info",
				"mainMaterial",
				"ocp",
				`Manual Color: ${JSON.stringify(manualColor)}`,
			);
		} else {
			createLog("info", "mainMaterial", "ocp", "Color check is not active.");
		}

		// // if we want to check the packaging
		const checkPKGSetting = set.filter((n) => n.name === "checkPKG");
		if (checkPKGSetting[0].value === "1") {
			const pkgAuto = checkCondition({
				results: res,
				lot,
				filterFn: (n) =>
					!n.IsMainMaterial && !n.isManual && "noPKGAutoShortage" in n,
				failCondition: (n) => n.noPKGAutoShortage === "noAutoPkg",
				failMessage: "for pkg",
				successMessage: "auto PKG is good",
			});
			if (!pkgAuto.success) return pkgAuto;
			createLog(
				"info",
				"mainMaterial",
				"ocp",
				`PKG Auto: ${JSON.stringify(pkgAuto)}`,
			);
			// 5. Packaging manual
			const pkgManual = checkCondition({
				results: res,
				lot,
				filterFn: (n) =>
					!n.IsMainMaterial && n.isManual && "noPKGManualShortage" in n,
				failCondition: (n) => n.noPKGManualShortage === "noManPkg",
				failMessage: "for pkg",
				successMessage: "manual PKG is good",
			});

			if (!pkgManual.success) return pkgManual;
			createLog(
				"info",
				"mainMaterial",
				"ocp",
				`PKG Manual: ${JSON.stringify(pkgManual)}`,
			);
		} else {
			createLog("info", "mainMaterial", "ocp", "PKG check is not active.");
		}

		// manual pkg
		if (checkPKGSetting[0].value === "1") {
			const packagingCheck = res.filter(
				(n: any) =>
					!n.IsMainMaterial && n.isManual && "noPKGManualShortage" in n,
			);
			if (
				packagingCheck.some((n: any) => n.noPKGManualShortage === "noManPkg")
			) {
				createLog(
					"info",
					"mainMaterial",
					"ocp",
					`lot: ${lot.lot}, is missing: ${packagingCheck
						.map(
							(o: any) =>
								`${o.MaterialHumanReadableId} - ${o.MaterialDescription}`,
						)
						.join(",\n ")} for pkg`,
				);
				return (isStaged = {
					message: `lot: ${lot.lot}, is missing: ${packagingCheck
						.map(
							(o: any) =>
								`${o.MaterialHumanReadableId} - ${o.MaterialDescription}`,
						)
						.join(",\n ")} for pkg`,
					success: false,
				});
			}
		} else {
			createLog("info", "mainMaterial", "ocp", "PKG check is not active.");
		}
	} catch (err) {
		createLog(
			"error",
			"mainMaterial",
			"ocp",
			`Error from running the Main Material query: ${err}`,
		);
	}
	return isStaged;
};
