"use client"
import { SearchJoResultRequest, fetchJos, updateJo } from "@/app/api/jo/actions";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Criterion } from "../SearchBox";
import SearchResults, { Column, defaultPagingController } from "../SearchResults/SearchResults";
import { EditNote } from "@mui/icons-material";
import { arrayToDateString, arrayToDateTimeString, integerFormatter } from "@/app/utils/formatUtil";
import { orderBy, uniqBy, upperFirst } from "lodash";
import SearchBox from "../SearchBox/SearchBox";
import { useRouter } from "next/navigation";
import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form";
import { StockInLineInput } from "@/app/api/stockIn";
import { JobOrder, JoDetailPickLine, JoStatus } from "@/app/api/jo";
import { Button, Stack } from "@mui/material";
import { BomCombo } from "@/app/api/bom";
import JoCreateFormModal from "./JoCreateFormModal";
import AddIcon from '@mui/icons-material/Add';
import QcStockInModal from "../PoDetail/QcStockInModal";
import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig";
import { createStockInLine } from "@/app/api/stockIn/actions";
import { msg } from "../Swal/CustomAlerts";
import dayjs from "dayjs";

import { fetchInventories } from "@/app/api/inventory/actions";
import { InventoryResult } from "@/app/api/inventory";
import { PrinterCombo } from "@/app/api/settings/printer";

interface Props {
    defaultInputs: SearchJoResultRequest,
    bomCombo: BomCombo[]
    printerCombo: PrinterCombo[];
}

type SearchQuery = Partial<Omit<JobOrder, "id">>;

type SearchParamNames = keyof SearchQuery;

const JoSearch: React.FC<Props> = ({ defaultInputs, bomCombo, printerCombo }) => {
    const { t } = useTranslation("jo");
    const router = useRouter()
    const [filteredJos, setFilteredJos] = useState<JobOrder[]>([]);
    const [inputs, setInputs] = useState(defaultInputs);
    const [pagingController, setPagingController] = useState(
        defaultPagingController
    )
    const [totalCount, setTotalCount] = useState(0)
    const [isCreateJoModalOpen, setIsCreateJoModalOpen] = useState(false)

    // console.log(inputs)
    const [inventoryData, setInventoryData] = useState<InventoryResult[]>([]);

    const [detailedJos, setDetailedJos] = useState<Map<number, JobOrder>>(new Map());

    const fetchJoDetailClient = async (id: number): Promise<JobOrder> => {
        const response = await fetch(`/api/jo/detail?id=${id}`);
        if (!response.ok) {
            throw new Error('Failed to fetch JO detail');
        }
        return response.json();
    };

    useEffect(() => {
        const fetchDetailedJos = async () => {
            const detailedMap = new Map<number, JobOrder>();
            
            for (const jo of filteredJos) {
                try {
                    const detailedJo = await fetchJoDetailClient(jo.id);  // Use client function
                    detailedMap.set(jo.id, detailedJo);
                } catch (error) {
                    console.error(`Error fetching detail for JO ${jo.id}:`, error);
                }
            }
            
            setDetailedJos(detailedMap);
        };

        if (filteredJos.length > 0) {
            fetchDetailedJos();
        }
    }, [filteredJos]);

    useEffect(() => {
    const fetchInventoryData = async () => {
        try {
            const inventoryResponse = await fetchInventories({
                code: "",
                name: "",
                type: "",
                pageNum: 0,
                pageSize: 1000 
            });
            setInventoryData(inventoryResponse.records);
        } catch (error) {
            console.error("Error fetching inventory data:", error);
        }
    };

        fetchInventoryData();
    }, []);

    const getStockAvailable = (pickLine: JoDetailPickLine) => {
        const inventory = inventoryData.find(inventory => 
            inventory.itemCode === pickLine.code || inventory.itemName === pickLine.name
        );
        
        if (inventory) {
            return inventory.availableQty || (inventory.onHandQty - inventory.onHoldQty - inventory.unavailableQty);
        }
        
        return 0;
    };

    const isStockSufficient = (pickLine: JoDetailPickLine) => {
        const stockAvailable = getStockAvailable(pickLine);
        return stockAvailable >= pickLine.reqQty;
    };

    const getStockCounts = (jo: JobOrder) => {
        const detailedJo = detailedJos.get(jo.id);
        
        if (!detailedJo?.pickLines || detailedJo.pickLines.length === 0) {
            return { total: 0, sufficient: 0, insufficient: 0 };
        }

        const totalLines = detailedJo.pickLines.length;
        const sufficientLines = detailedJo.pickLines.filter(pickLine => isStockSufficient(pickLine)).length;
        const insufficientLines = totalLines - sufficientLines;

        return {
            total: totalLines,
            sufficient: sufficientLines,
            insufficient: insufficientLines
        };
    };

    const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => [
        { label: t("Code"), paramName: "code", type: "text" },
        { label: t("Item Name"), paramName: "itemName", type: "text" },
        { label: t("Plan Start"), label2: t("Plan Start To"), paramName: "planStart", type: "datetimeRange" },
    ], [t])

    const columns = useMemo<Column<JobOrder>[]>(
        () => [
            {
                name: "code",
                label: t("Code"),
                flex: 2
            },
            {
                name: "item",
                label: t("Item Code"),
                renderCell: (row) => {
                    return row.item ? t(row.item.code) : '-'
                }
            },
            {
                name: "itemName",
                label: t("Item Name"),
                renderCell: (row) => {
                    return row.item ? t(row.item.name) : '-'
                }
            },
            {
                name: "reqQty",
                label: t("Req. Qty"),
                align: "right",
                headerAlign: "right",
                renderCell: (row) => {
                    return integerFormatter.format(row.reqQty)
                }
            },
            {
                name: "item",
                label: t("UoM"),
                align: "left",
                headerAlign: "left",
                renderCell: (row) => {
                    return row.item?.uom ? t(row.item.uom.udfudesc) : '-'
                }
            },
            {
                name: "status",
                label: t("Status"),
                renderCell: (row) => {  // TODO improve
                    return <span style={{color: row.stockInLineStatus == "escalated" ? "red" : "inherit"}}>
                        {t(upperFirst(row.status))}
                    </span>
                }
            },{
                name: "planStart",
                label: t("Estimated Production Date"),
                align: "left",
                headerAlign: "left",
                renderCell: (row) => {
                    return row.planStart ? arrayToDateTimeString(row.planStart) : '-'
                }
            },
            {
                name: "stockStatus" as keyof JobOrder,
                label: t("BOM Status"),
                align: "left",
                headerAlign: "left",
                renderCell: (row) => {
                    const stockCounts = getStockCounts(row);
                    return (
                        <span style={{ color: stockCounts.insufficient > 0 ? 'red' : 'green' }}>
                            {stockCounts.sufficient}/{stockCounts.total}
                        </span>
                    );
                }
            },
            {
                // TODO put it inside Action Buttons
                name: "id",
                label: t("Actions"),
                // onClick: (record) => onDetailClick(record),
                // buttonIcon: <EditNote />,
                renderCell: (row) => { 
                    const btnSx = getButtonSx(row);
                    return (
                        <Button
                        id="emailSupplier"
                        type="button"
                        variant="contained"
                        color="primary"
                        sx={{  width: "150px", backgroundColor: btnSx.color }}
                        // disabled={params.row.status != "rejected" && params.row.status != "partially_completed"}
                        onClick={() => onDetailClick(row)}
                        >{btnSx.label}</Button>
                    )
                }
            },
        ], [inventoryData]
    )

    const handleUpdate = useCallback(async (jo: JobOrder) => {
        console.log(jo);
        try {
            // setIsUploading(true)
            if (jo.id) {
                const response = await updateJo({ id: jo.id, status: "storing" });
                console.log(`%c Updated JO:`, "color:lime", response);
                const postData = {
                    itemId: jo?.item?.id!!,
                    acceptedQty: jo?.reqQty ?? 1,
                    productLotNo: jo?.code,
                    productionDate: arrayToDateString(dayjs(), "input"),
                    jobOrderId: jo?.id,
                    // acceptedQty: secondReceiveQty || 0,
                    // acceptedQty: row.acceptedQty,
                };
                const res = await createStockInLine(postData);
                console.log(`%c Created Stock In Line`, "color:lime", res);
                msg(t("update success"));
                refetchData(defaultInputs, "search");
            }

        } catch (e) {
            // backend error
            // setServerError(t("An error has occurred. Please try again later."));
            console.log(e);
        } finally {
            // setIsUploading(false)
        }
    }, [])

    const refetchData = useCallback(async (
        query: Record<SearchParamNames, string> | SearchJoResultRequest,
        actionType: "reset" | "search" | "paging",
    ) => {
        const params: SearchJoResultRequest = {
            code: query.code,
            itemName: query.itemName,
            planStart: query.planStart,
            planStartTo: query.planStartTo,
            pageNum: pagingController.pageNum - 1,
            pageSize: pagingController.pageSize,
        }
        const response = await fetchJos(params)

        if (response) {
            setTotalCount(response.total);
            switch (actionType) {
                case "reset":
                case "search":
                    setFilteredJos(() => orderBy(response.records, ["id"], ["desc"]));
                    break;
                case "paging":
                    setFilteredJos((fs) =>
                        orderBy(uniqBy([...fs, ...response.records], "id"), ["id"], ["desc"]),
                    );
                    break;
            }
        }
    }, [pagingController, setPagingController])

    const searchDataByPage = useCallback(() => {
        refetchData(inputs, "paging");
    }, [inputs])
    useEffect(() => {
        searchDataByPage();
    }, [pagingController]);

    const getButtonSx = (jo : JobOrder) => { // TODO put it in ActionButtons.ts
        const joStatus = jo.status?.toLowerCase();
        const silStatus = jo.stockInLineStatus?.toLowerCase();
        let btnSx = {label:"", color:""};
        switch (joStatus) {
          case "planning": btnSx = {label: t("release jo"), color:"primary.main"}; break;
          case "pending": btnSx = {label: t("scan picked material"), color:"error.main"}; break;
          case "processing": btnSx = {label: t("complete jo"), color:"warning.main"}; break;
        //   case "packaging":
        //   case "storing": btnSx = {label: t("view putaway"), color:"secondary.main"}; break;
          case "storing":
            switch (silStatus) {
                case "pending": btnSx = {label: t("process epqc"), color:"success.main"}; break;
                case "received": btnSx = {label: t("view putaway"), color:"secondary.main"}; break;
                case "escalated":
                    if (sessionToken?.id == jo.silHandlerId) {
                        btnSx = {label: t("escalation processing"), color:"warning.main"};
                        break;
                    }
                default: btnSx = {label: t("view stockin"), color:"info.main"};
            } 
            break;
          case "completed": btnSx = {label: t("view stockin"), color:"info.main"}; break;
          default: btnSx = {label: t("scan picked material"), color:"success.main"};
        }
        return btnSx
    };

    const { data: session } = useSession();
    const sessionToken = session as SessionWithTokens | null;

    const [openModal, setOpenModal] = useState<boolean>(false);
    const [modalInfo, setModalInfo] = useState<StockInLineInput>();

    const onDetailClick = useCallback((record: JobOrder) => {

        if (record.status == "processing") {
            handleUpdate(record)
        } else if (record.status == "storing" || record.status == "completed") {
            if (record.stockInLineId != null) {
                const data = {
                    id: record.stockInLineId,
                    expiryDate: arrayToDateString(dayjs().add(1, "month"), "input"),
                }
                setModalInfo(data);
                setOpenModal(true);
            } else { alert('Invalid Stock In Line Id'); }
        } else {
            router.push(`/jo/edit?id=${record.id}`)
        }
    }, [])

    const closeNewModal = useCallback(() => {
        // const response = updateJo({ id: 1, status: "storing" });
        setOpenModal(false); // Close the modal first
        // setTimeout(() => {
        //   }, 300); // Add a delay to avoid immediate re-trigger of useEffect
        refetchData(defaultInputs, "search");
    }, []);

    const onSearch = useCallback((query: Record<SearchParamNames, string>) => {
        setInputs(() => ({
            code: query.code,
            itemName: query.itemName,
            planStart: query.planStart,
            planStartTo: query.planStartTo
        }))
        refetchData(query, "search");
    }, [])

    const onReset = useCallback(() => {
        refetchData(defaultInputs, "paging");
    }, [])

    // Manual Create Jo Related

    const onOpenCreateJoModal = useCallback(() => {
        setIsCreateJoModalOpen(() => true)
    }, [])

    const onCloseCreateJoModal = useCallback(() => {
        setIsCreateJoModalOpen(() => false)
    }, [])

    return <>
        <Stack
            direction="row"
            justifyContent="flex-end"
            spacing={2}
            sx={{ mt: 2 }}
        >
            <Button
                variant="outlined"
                startIcon={<AddIcon />}
                onClick={onOpenCreateJoModal}
            >
                {t("Create Job Order")}
            </Button>
        </Stack>
        <SearchBox
            criteria={searchCriteria}
            onSearch={onSearch}
            onReset={onReset}
        />
        <SearchResults<JobOrder>
            items={filteredJos}
            columns={columns}
            setPagingController={setPagingController}
            pagingController={pagingController}
            totalCount={totalCount}
        // isAutoPaging={false}
        />
        <JoCreateFormModal
            open={isCreateJoModalOpen}
            bomCombo={bomCombo}
            onClose={onCloseCreateJoModal}
            onSearch={searchDataByPage}
        />

        <QcStockInModal
            session={sessionToken}
            open={openModal}
            onClose={closeNewModal}
            inputDetail={modalInfo}
            printerCombo={printerCombo}
            // skipQc={true}
        />
    </>
}

export default JoSearch;