import { create } from "zustand";
import { immer } from "zustand/middleware/immer";

interface AisleStore {
    aisles: Aisles;
    setAisles: (aisles: Aisles) => Aisles;
    addAisle: (aisle: Aisle) => Aisle;
    updateAisle: (uuid: string, updated: Partial<Aisle>) => Aisle | undefined;
    removeAisle: (uuid: string) => Aisle | undefined;
    removePoint: (uuid: string) => Aisles;
    clearAisles: () => Aisles;
    setPosition: (
        pointUuid: string,
        position: [number, number, number]
    ) => Aisle | undefined;
    setLayer: (pointUuid: string, layer: number) => Aisle | undefined;
    setColor: (aisleUuid: string, color: AisleColors) => Aisle | undefined;

    setSolidAisleWidth: (aisleUuid: string, width: number) => Aisle | undefined;
    setDashedAisleProperties: (
        aisleUuid: string,
        props: { aisleWidth?: number; dashLength?: number; gapLength?: number }
    ) => Aisle | undefined;
    setDottedAisleProperties: (
        aisleUuid: string,
        props: { dotRadius?: number; gapLength?: number }
    ) => Aisle | undefined;
    setArrowAisleWidth: (aisleUuid: string, width: number) => Aisle | undefined;
    setArrowsAisleProperties: (
        aisleUuid: string,
        props: { aisleWidth?: number; aisleLength?: number; gapLength?: number }
    ) => Aisle | undefined;
    setArcAisleWidth: (
        aisleUuid: string,
        props: { aisleWidth?: number; isFlipped: boolean }
    ) => Aisle | undefined;
    setCircleAisleWidth: (aisleUuid: string, width: number) => Aisle | undefined;
    setJunctionAisleProperties: (
        aisleUuid: string,
        props: { aisleWidth?: number; isFlipped: boolean }
    ) => Aisle | undefined;

    getAisleById: (uuid: string) => Aisle | undefined;
    getAislesByPointId: (uuid: string) => Aisle[] | [];
    getAislePointById: (uuid: string) => Point | undefined;
    getConnectedPoints: (uuid: string) => Point[] | [];
    getAisleType: <T extends AisleType>(uuid: string) => T | undefined;
}

export const createAisleStore = () => {
    return create<AisleStore>()(
        immer((set, get) => ({
            aisles: [],

            setAisles: (aisles) => {
                set((state) => {
                    state.aisles = aisles;
                });
                return aisles;
            },

            addAisle: (aisle) => {
                set((state) => {
                    state.aisles.push(aisle);
                });
                return aisle;
            },

            updateAisle: (uuid, updated) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === uuid);
                    if (aisle) {
                        Object.assign(aisle, updated);
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            removeAisle: (uuid) => {
                let removedAisle: Aisle | undefined;
                set((state) => {
                    const index = state.aisles.findIndex((a) => a.aisleUuid === uuid);
                    if (index !== -1) {
                        removedAisle = JSON.parse(JSON.stringify(state.aisles[index]));
                        state.aisles.splice(index, 1);
                    }
                });
                return removedAisle;
            },

            removePoint: (uuid) => {
                const removedAisles: Aisle[] = [];
                set((state) => {
                    state.aisles = state.aisles.filter((aisle) => {
                        const hasPoint = aisle.points.some(
                            (point) => point.pointUuid === uuid
                        );
                        if (hasPoint) {
                            removedAisles.push(JSON.parse(JSON.stringify(aisle)));
                            return false;
                        }
                        return true;
                    });
                });
                return removedAisles;
            },

            clearAisles: () => {
                const clearedAisles = get().aisles;
                set((state) => {
                    state.aisles = [];
                });
                return clearedAisles;
            },

            setPosition: (pointUuid, position) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    for (const aisle of state.aisles) {
                        const point = aisle.points.find((p) => p.pointUuid === pointUuid);
                        if (point) {
                            point.position = position;
                            updatedAisle = JSON.parse(JSON.stringify(aisle));
                        }
                    }
                });
                return updatedAisle;
            },

            setLayer: (pointUuid, layer) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    for (const aisle of state.aisles) {
                        const point = aisle.points.find((p) => p.pointUuid === pointUuid);
                        if (point) {
                            point.layer = layer;
                            updatedAisle = JSON.parse(JSON.stringify(aisle));
                        }
                    }
                });
                return updatedAisle;
            },

            setColor: (aisleUuid, color) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle) {
                        aisle.type.aisleColor = color;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            setSolidAisleWidth: (aisleUuid, width) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle && aisle.type.aisleType === "solid-aisle") {
                        aisle.type.aisleWidth = width;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            setDashedAisleProperties: (aisleUuid, props) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle && aisle.type.aisleType === "dashed-aisle") {
                        if (props.aisleWidth !== undefined)
                            aisle.type.aisleWidth = props.aisleWidth;
                        if (props.dashLength !== undefined)
                            aisle.type.dashLength = props.dashLength;
                        if (props.gapLength !== undefined)
                            aisle.type.gapLength = props.gapLength;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            setDottedAisleProperties: (aisleUuid, props) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle && aisle.type.aisleType === "dotted-aisle") {
                        if (props.dotRadius !== undefined)
                            aisle.type.dotRadius = props.dotRadius;
                        if (props.gapLength !== undefined)
                            aisle.type.gapLength = props.gapLength;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            setArrowAisleWidth: (aisleUuid, width) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle && aisle.type.aisleType === "arrow-aisle") {
                        aisle.type.aisleWidth = width;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            setArrowsAisleProperties: (aisleUuid, props) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle && aisle.type.aisleType === "arrows-aisle") {
                        if (props.aisleWidth !== undefined)
                            aisle.type.aisleWidth = props.aisleWidth;
                        if (props.aisleLength !== undefined)
                            aisle.type.aisleLength = props.aisleLength;
                        if (props.gapLength !== undefined)
                            aisle.type.gapLength = props.gapLength;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            setArcAisleWidth: (aisleUuid, props) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle && aisle.type.aisleType === "arc-aisle") {
                        if (props.aisleWidth !== undefined)
                            aisle.type.aisleWidth = props.aisleWidth;
                        if (props.isFlipped !== undefined)
                            aisle.type.isFlipped = props.isFlipped;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            setCircleAisleWidth: (aisleUuid, width) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle && aisle.type.aisleType === "circle-aisle") {
                        aisle.type.aisleWidth = width;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            setJunctionAisleProperties: (aisleUuid, props) => {
                let updatedAisle: Aisle | undefined;
                set((state) => {
                    const aisle = state.aisles.find((a) => a.aisleUuid === aisleUuid);
                    if (aisle && aisle.type.aisleType === "junction-aisle") {
                        if (props.aisleWidth !== undefined)
                            aisle.type.aisleWidth = props.aisleWidth;
                        if (props.isFlipped !== undefined)
                            aisle.type.isFlipped = props.isFlipped;
                        updatedAisle = JSON.parse(JSON.stringify(aisle));
                    }
                });
                return updatedAisle;
            },

            getAisleById: (uuid) => {
                return get().aisles.find((a) => a.aisleUuid === uuid);
            },

            getAislesByPointId: (uuid) => {
                return get().aisles.filter((a) => {
                    return a.points.some((p) => p.pointUuid === uuid);
                })
            },

            getAislePointById: (uuid) => {
                for (const aisle of get().aisles) {
                    const point = aisle.points.find((p) => p.pointUuid === uuid);
                    if (point) {
                        return point;
                    }
                }
                return undefined;
            },

            getConnectedPoints: (uuid) => {
                const connected: Point[] = [];
                for (const aisle of get().aisles) {
                    for (const point of aisle.points) {
                        if (point.pointUuid === uuid) {
                            connected.push(...aisle.points.filter((p) => p.pointUuid !== uuid));
                        }
                    }
                }
                return connected;
            },

            getAisleType: <T extends AisleType>(uuid: string) => {
                const aisle = get().aisles.find((a) => a.aisleUuid === uuid);
                return aisle?.type as T | undefined;
            },
        }))
    )
}

export type AisleStoreType = ReturnType<typeof createAisleStore>;