/**
 * This will monitor alpla purchase
 */

import { eq, sql } from "drizzle-orm";
import { db } from "../db/db.controller.js";
import {
	alplaPurchaseHistory,
	type NewAlplaPurchaseHistory,
} from "../db/schema/alplapurchase.schema.js";
import { settings } from "../db/schema/settings.schema.js";
import { createLogger } from "../logger/logger.controller.js";
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
import {
	type SqlQuery,
	sqlQuerySelector,
} from "../prodSql/prodSqlQuerySelector.utils.js";
import type { GpStatus, StatusUpdate } from "../types/purhcaseTypes.js";
import { createCronJob } from "../utils/croner.utils.js";
import { delay } from "../utils/delay.utils.js";
import { returnFunc } from "../utils/returnHelper.utils.js";
import { tryCatch } from "../utils/trycatch.utils.js";
import { gpReqCheck } from "./puchase.gpCheck.js";

const log = createLogger({ module: "purchase", subModule: "purchaseMonitor" });

export const monitorAlplaPurchase = async () => {
	const purchaseMonitor = await db
		.select()
		.from(settings)
		.where(eq(settings.name, "purchaseMonitor"));

	const sqlQuery = sqlQuerySelector(`alplapurchase`) as SqlQuery;

	if (!sqlQuery.success) {
		return returnFunc({
			success: false,
			level: "error",
			module: "purchase",
			subModule: "query",
			message: `Error getting alpla purchase info`,
			data: sqlQuery.message as any,
			notify: true,
		});
	}

	if (purchaseMonitor[0]?.active) {
		createCronJob("purchaseMonitor", "0 5 * * * *", async () => {
			try {
				const result = await prodQuery(
					sqlQuery.query.replace(
						"[interval]",
						`${purchaseMonitor[0]?.value || "5"}`,
					),
					"Get release info",
				);

				log.debug(
					{},
					`There are ${result.data.length} pending to be updated from the last ${purchaseMonitor[0]?.value}`,
				);
				if (result.data.length) {
					const convertedData = result.data.map((i) => ({
						...i,
						position: JSON.parse(i.position),
					})) as NewAlplaPurchaseHistory;

					const { data, error } = await tryCatch(
						db.insert(alplaPurchaseHistory).values(convertedData).returning(),
					);

					if (data) {
						log.debug(
							{ data },
							"New data was just added to alpla purchase history",
						);
					}

					if (error) {
						log.error(
							{ error, notify: true },
							"There was an error adding alpla purchase history",
						);
					}

					await delay(500);
				}
			} catch (e) {
				log.error(
					{ error: e, notify: true },
					"Error occurred while running the monitor job",
				);

				return;
			}

			// re-pull re-pull everything that has approvedStatus is pending

			const { data: allReq, error: errorReq } = await tryCatch(
				db
					.select()
					.from(alplaPurchaseHistory)
					.where(eq(alplaPurchaseHistory.approvedStatus, "new")),
			);

			// if theres no reqs just end meow
			if (errorReq) {
				log.error(
					{ stack: errorReq, notify: true },
					"There was an error getting history data",
				);
				return;
			}

			log.debug({}, `There are ${allReq.length} pending reqs to be updated`);

			if (!allReq.length) {
				log.debug({}, "There are not reqs to be processed");
				return;
			}
			/**
			 * approvedStatus
			 * remark = '' then pending req/manual po
			 * pending = pending
			 * approved = approved
			 *
			 */

			// the flow for all the fun stuff

			const needsGpLookup: GpStatus[] = [];
			const updates: StatusUpdate[] = [];

			for (const row of allReq ?? []) {
				const remark = row.remark?.toLowerCase() ?? "";

				if (remark === "") {
					updates.push({ id: row.id, approvedStatus: "initial" });
					continue;
				}

				if (remark.includes("rct")) {
					updates.push({ id: row.id, approvedStatus: "received" });
					continue;
				}

				if (remark.includes("apo")) {
					updates.push({ id: row.id, approvedStatus: "approved" });
					continue;
				}

				// not handled locally, defer to GP lookup
				needsGpLookup.push({ id: row.id, req: row.remark?.trim() ?? "" });
			}

			const gpSmash = (await gpReqCheck(needsGpLookup)) as StatusUpdate[];

			const merge = [...updates, ...gpSmash];

			if (merge.length > 0) {
				await db.execute(sql`
					UPDATE ${alplaPurchaseHistory}
					SET approved_status = CASE
						${sql.join(
							merge.map(
								(row) =>
									sql`WHEN ${alplaPurchaseHistory.id} = ${row.id} THEN ${row.approvedStatus}`,
							),
							sql` `,
						)}
						ELSE approved_status
					END,
					updated_at = NOW()
					WHERE ${alplaPurchaseHistory.id} IN (
						${sql.join(
							merge.map((row) => sql`${row.id}`),
							sql`, `,
						)}
					)
				`);
				log.info(
					{},
					"All alpla purchase orders have been processed and updated",
				);
			}

			// for reqs, create a string of reqs then run them through the gp req table to see there status. then update in lst ass see fit.

			// then double check if we have all reqs covered, for the reqs missing from above restring them and check the po table

			// these ones will be called to as converted to po

			// for the remaining reqs from above check the actual req table to see the status of it if the workflow is set at Recall this means a change was requested from purchasing team and needs to be re approved

			// for all remaining reqs we change them to replace/canceled
		});
	}
};

// const updates = (allReq ?? [])
// 	.map((row) => {
// 		const remark = row.remark?.toLowerCase() ?? "";

// 		let approvedStatus: string | null = null;

// 		// priority order matters here
// 		if (remark === "") {
// 			approvedStatus = "initial";
// 		} else if (remark.includes("rct")) {
// 			approvedStatus = "received";
// 		} else if (remark.includes("apo")) {
// 			approvedStatus = "approved";
// 		}

// 		// add your next 4 checks here
// 		// else if (...) approvedStatus = "somethingElse";

// 		if (!approvedStatus) return null;

// 		return {
// 			id: row.id,
// 			approvedStatus,
// 		};
// 	})
// 	.filter(
// 		(
// 			row,
// 		): row is {
// 			id: string;
// 			approvedStatus: string;
// 		} => row !== null,
// 	);
