import { createContext, Dispatch, FC, SetStateAction, useContext, useState } from "react";
import { ClientSchema } from "../../../../../client";
import { ReceiptBox, ReceiptPallet } from "../types/types.tsx";
import { modals } from "@mantine/modals";
import nextId from "../utils/nextId.ts";
import { useListState, UseListStateHandlers } from "@mantine/hooks";
import useScanningMode, { ScanningData } from "../../../hooks/useScanningMode.tsx";
import useBarcodesProductsMap from "../../../hooks/useBarcodesProductsMap.tsx";
import useApplyingScanningResult from "../hooks/useApplyingScannedResult.tsx";

type ReceiptContextState = {
    client?: ClientSchema;
    setClient: Dispatch<SetStateAction<ClientSchema | undefined>>;
    fixed: boolean;
    setFixed: Dispatch<SetStateAction<boolean>>;

    pallets: ReceiptPallet[];
    palletsHandlers: UseListStateHandlers<ReceiptPallet>;
    boxes: ReceiptBox[];
    boxesHandlers: UseListStateHandlers<ReceiptBox>;

    nextId: () => number;
    onObjectEditClick: (object: ReceiptBox | ReceiptPallet, isBox: boolean, parentPallet?: ReceiptPallet) => void;
    reset: () => void;
    setBoxData: (box: ReceiptBox, pallet?: ReceiptPallet) => void;
    setPalletData: (pallet: ReceiptPallet) => void;

    scanningData: ScanningData;
    toggleScanning: (boxId?: number, palletId?: number) => void;
};

const ReceiptContext = createContext<ReceiptContextState | undefined>(
    undefined,
);

const useReceiptContextState = () => {
    const [client, setClient] = useState<ClientSchema>();
    const [fixed, setFixed] = useState<boolean>(false);

    const [pallets, palletsHandlers] = useListState<ReceiptPallet>([]);
    const [boxes, boxesHandlers] = useListState<ReceiptBox>([]);

    const { barcodesProductsMap } = useBarcodesProductsMap({ clientId: client?.id });

    const setBoxData = (box: ReceiptBox, pallet?: ReceiptPallet) => {
        if (pallet) {
            setBoxOnPalletData(box, pallet);
        } else {
            setBoxWithoutPalletData(box);
        }
    };

    const setBoxWithoutPalletData = (box: ReceiptBox) => {
        const boxIdx = boxes.findIndex(item => item.id === box.id);
        if (boxIdx === -1) {
            boxesHandlers.append(box);
        } else {
            boxesHandlers.setItem(boxIdx, box);
        }
    };

    const setBoxOnPalletData = (box: ReceiptBox, pallet: ReceiptPallet) => {
        const palletIdx = pallets.findIndex(p => p.id === pallet.id);
        const boxIdx = pallets[palletIdx].boxes.findIndex(b => b.id === box.id);
        if (boxIdx === -1) {
            palletsHandlers.setItemProp(palletIdx, "boxes", [box, ...boxes]);
        } else {
            pallets[palletIdx].boxes[boxIdx] = box;
            palletsHandlers.setState(pallets);
        }
        palletsHandlers.setState([...pallets]);
    };

    const setPalletData = (pallet: ReceiptPallet) => {
        const palletIdx = pallets.findIndex(p => p.id === pallet.id);
        if (palletIdx !== -1) {
            palletsHandlers.setItem(palletIdx, pallet);
            palletsHandlers.setState([...pallets]);
        }
    };

    const editObject = (
        object: ReceiptBox | ReceiptPallet,
        isBox: boolean,
        parentPallet?: ReceiptPallet,
    ) => {
        if (isBox) setBoxData(object, parentPallet);
        setPalletData(object as ReceiptPallet);
    };

    const onObjectEditClick = (
        object: ReceiptBox | ReceiptPallet,
        isBox: boolean,
        parentPallet?: ReceiptPallet,
    ) => {
        if (!client) return;
        modals.openContextModal({
            modal: "newReceiptModal",
            title: "Добавление товара",
            withCloseButton: false,
            innerProps: {
                clientId: client.id,
                object: object,
                setObjectData: (object: ReceiptBox | ReceiptPallet) => {
                    editObject(object, isBox, parentPallet);
                },
                barcodesProductsMap,
            },
        });
    };

    const {
        onScanningFinish,
    } = useApplyingScanningResult({
        pallets,
        boxes,
        barcodesProductsMap,
        editObject,
    });

    const { scanningData, toggleScanning } = useScanningMode({ onScanningFinish });

    const reset = () => {
        palletsHandlers.setState([]);
        boxesHandlers.setState([]);
        setFixed(false);
        setClient(undefined);
    };

    return {
        client,
        setClient,
        fixed,
        setFixed,
        pallets,
        palletsHandlers,
        boxes,
        boxesHandlers,
        nextId,
        onObjectEditClick,
        reset,
        setBoxData,
        setPalletData,
        scanningData,
        toggleScanning,
    };
};

type ReceiptContextProviderProps = {
    children: React.ReactNode;
};

export const ReceiptContextProvider: FC<ReceiptContextProviderProps> = ({ children }) => {
    const state = useReceiptContextState();
    return (
        <ReceiptContext.Provider value={state}>
            {children}
        </ReceiptContext.Provider>
    );
};

export const useReceiptContext = () => {
    const context = useContext(ReceiptContext);
    if (!context) {
        throw new Error(
            "useReceiptContext must be used within a ReceiptContextProvider",
        );
    }
    return context;
};
