import { db } from "../../../../../database/dbclient.js";
import { settings } from "../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js";
import { getLots } from "../lots/lots.js";
import { billingCheck } from "../specialProcesses/billingCheck/billingCheck.js";
import { isMainMatStaged } from "../materials/mainMaterial.js";
import { firstLotLabel } from "../specialProcesses/lotChangeLabel/lotCHangeLabel.js";
import { prolinkCheck } from "../lots/prolinkCheck.js";
import { createLabel } from "./createLabel.js";
import { bookInLabel } from "./bookIn.js";
import { delieryInhouse } from "../specialProcesses/inhouse/inhouseDelivery.js";
import { dualPrintingProcess } from "../specialProcesses/dualPrinting/dualPrinting.js";
import { getMac } from "../../utils/getMachineId.js";

interface Printer {
    name: string;
    humanReadableId: string;
    // Add any other expected properties
}

export const labelingProcess = async ({
    line = null as string | null,
    printer = null as Printer | null,
    userPrinted = null,
    rfidTag = null,
} = {}) => {
    /**
     * Creates a label once all logic is passed
     */
    let filteredLot: any = [];
    createLog("debug", "labeling", "ocp", `Starting labeling process`);
    const { data: settingData, error: settingError } = await tryCatch(
        db.select().from(settings)
    );

    if (settingError) {
        return {
            success: false,
            message: "There was an error getting the settings.",
            settingError,
        };
    }
    // get the plantToken
    const plantToken = settingData.filter((n) => n.name === "plantToken");

    // get the current lots
    const lots = await getLots();

    // if we got a line passed over we need to get the machine id from this.
    if (line) {
        const macId = await getMac(line);
        // filter out the lot for the line
        filteredLot = lots.data.filter(
            (l: any) => l.MachineID === macId[0]?.HumanReadableId
        );

        if (filteredLot.length === 0) {
            createLog(
                "error",
                "labeling",
                "ocp",
                `There is not a lot assigned to ${line}.`
            );
            return {
                success: false,
                message: `There is not a lot assigned to ${line}.`,
            };
        }
    }

    // if we came from a printer
    if (printer) {
        // filter the lot based on the printerID
        // console.log(printer);
        filteredLot = lots.data.filter(
            (l: any) => l.printerID === parseInt(printer?.humanReadableId)
        );
        if (filteredLot.length === 0) {
            // console.log(`There is not a lot assigned to ${printer.name}`);
            createLog(
                "error",
                "labeling",
                "ocp",
                `There is not a lot assigned to ${printer.name}`
            );
            //printerUpdate(printer, 7, `There is no lot assigned to this printer.`);
            return {
                success: false,
                message: `There is not a lot assigned to ${printer.name}.`,
            };
        }
    }

    /**
     *
     * The checks we do before we can actually print a label will take place meow.
     *
     */

    // if the plant does not want to have dual printing  and we have >2 assigned well return and send error.
    let dualPrinting = settingData.filter((d) => d.name === "dualPrinting")[0]
        ?.value;

    if (filteredLot.length > 1 && dualPrinting === "0") {
        createLog(
            "error",
            "labeling",
            "ocp",
            `${printer?.name}, has more than one lot assigned to it, and dual printing shut off.`
        );
        return {
            success: false,
            message: `${printer?.name}, has more than one lot assigned to it, and dual printing shut off.`,
        };
    }

    if (filteredLot.length > 1 && dualPrinting === "1") {
        // send over for dual printing processing
        createLog(
            "info",
            "labeling",
            "ocp",
            `${printer?.name}, being sent over for dual printing processing.`
        );
        // process what line to print the label for and return the lot info and change filteredLot to returned one.
        filteredLot = await dualPrintingProcess(filteredLot);
    }

    // if there are more than 2 lots it might be an auto labeler, autolabeler will be defined by its id for now only dayton
    if (filteredLot?.length > 2 && plantToken[0].value !== "usday1") {
        createLog(
            "error",
            "labeling",
            "ocp",
            `${printer?.name}, has more than 2 lot assigned to it, and not in ${plantToken[0].value}`
        );
        return {
            success: false,
            message: `${printer?.name}, has more than 2 lot assigned to it, and not in ${plantToken[0].value}`,
        };
    }

    // special process for florence
    const isBillingTime = await billingCheck();

    if (isBillingTime) {
        // billing is inside the window we dont want to bill now.
        return {
            success: false,
            message: "Billing time cant print.",
        };
    }

    // check if we actaully have a lot passed over so we do not error out again.
    if (filteredLot.length === 0) {
        createLog(
            "error",
            "labeling",
            "ocp",
            `Error getting lot info from ${
                printer ? printer.name : "Missing printer info"
            }`
        );
        return {
            success: false,
            message: `Error getting lot info from ${
                printer ? printer.name : "Missing printer info"
            }`,
        };
    }

    // check mm is good
    const mmStaged = await isMainMatStaged(filteredLot[0]);

    if (!mmStaged) {
        createLog(
            "error",
            "labeling",
            "ocp",
            `Main material is not prepaired for lot ${filteredLot[0].lot}`
        );

        return {
            success: false,
            message: `Main material is not prepaired for lot ${filteredLot[0].lot}`,
        };
    }

    // comment only but will check for color
    createLog(
        "info",
        "labeling",
        "ocp",
        `Remaining pallets for: ${filteredLot[0].MachineDescription} is ${filteredLot[0].Remaining}`
    );

    // do we want to over run
    if (filteredLot[0].overPrinting === "no" && filteredLot[0].Remaining <= 0) {
        createLog(
            "error",
            "labeling",
            "ocp",
            `Over Printing on ${filteredLot[0].MachineDescription} is not allowed please change the lot`
        );
        // for slc we want to run the first label for henkel
        firstLotLabel(filteredLot[0]);
        return {
            success: false,
            message: `Over Printing on ${filteredLot[0].MachineDescription} is not allowed please change the lot`,
        };
    }

    // prolink check by lot
    const prolink = await prolinkCheck(filteredLot[0].lot);

    if (!prolink) {
        //console.error(`Prolink does not match for ${filteredLot[0].MachineDescription}`);
        createLog(
            "error",
            "labeling",
            "ocp",
            `Prolink does not match for ${filteredLot[0].MachineDescription}`
        );
        return {
            success: false,
            message: `Prolink does not match for ${filteredLot[0].MachineDescription}`,
        };
    }
    createLog("info", "labeling", "ocp", `Is prolink good? ${prolink}`);

    // create the label
    const label = await createLabel(filteredLot[0], userPrinted);

    if (!label.success) {
        createLog(
            "error",
            "labeling",
            "ocp",
            `There was an error creating the label: ${label.message}`
        );
        return { sucess: false, message: label.message, data: label.data };
    }

    // send over to be booked in if we can do it.
    const bookin = settingData.filter((s) => s.name === "bookin");
    let book: any = [];
    if (bookin[0].value === "1") {
        book = await bookInLabel(label.data);
    } else {
        createLog("info", "labeling", "ocp", "Bookin is turned off.");

        // will add later!!! :P
    }

    // inhouse - if the inhouse funtion is turned on we will deliver to inhouse as long as we did not hit an error state
    const inhouseDelivery = settingData.filter(
        (s) => s.name === "inhouseDelivery"
    );
    if (inhouseDelivery[0].value === "1") {
        const deliverPallet = await delieryInhouse(book.data);
        // console.log(deliverPallet);
    }

    return {
        success: true,
        message: "Label fully processed.",
        data: label.data,
    };
};
