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

interface HumansStore {
    humans: HumanStatus[];

    addHuman: (productUuid: string, event: HumanEventSchema) => void;
    removeHuman: (modelUuid: string) => void;
    updateHuman: (
        modelUuid: string,
        updates: Partial<Omit<HumanStatus, "modelUuid" | "productUuid">>
    ) => void;
    clearHumans: () => void;

    setCurrentPhase: (modelUuid: string, phase: string) => void;

    addCurrentAction: (modelUuid: string, actionUuid: string) => void;
    removeCurrentAction: (modelUuid: string) => void;

    setHumanActive: (modelUuid: string, isActive: boolean) => void;
    setHumanScheduled: (modelUuid: string, isPicking: boolean) => void;
    setHumanLoad: (modelUuid: string, load: number) => void;
    setHumanState: (
        modelUuid: string,
        newState: HumanStatus["state"]
    ) => void;
    incrementHumanLoad: (modelUuid: string, incrementBy: number) => void;
    decrementHumanLoad: (modelUuid: string, decrementBy: number) => void;

    addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
    setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void;
    removeLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
    getLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
    clearCurrentMaterials: (modelUuid: string) => void;

    incrementActiveTime: (modelUuid: string, incrementBy: number) => void;
    incrementIdleTime: (modelUuid: string, incrementBy: number) => void;
    incrementDistanceTraveled: (modelUuid: string, incrementBy: number) => void;
    resetTime: (modelUuid: string) => void;

    getHumanById: (modelUuid: string) => HumanStatus | undefined;
    getHumansByProduct: (productUuid: string) => HumanStatus[];
    getActiveHumans: () => HumanStatus[];
}

export const createHumanStore = () => {
    return create<HumansStore>()(
        immer((set, get) => ({
            humans: [],

            addHuman: (productUuid, event) => {
                set((state) => {
                    const exists = state.humans.some(h => h.modelUuid === event.modelUuid);
                    if (!exists) {
                        state.humans.push({
                            ...event,
                            productUuid,
                            currentPhase: 'init',
                            isActive: false,
                            isScheduled: false,
                            idleTime: 0,
                            activeTime: 0,
                            currentLoad: 0,
                            currentMaterials: [],
                            distanceTraveled: 0
                        });
                    }
                });
            },

            removeHuman: (modelUuid) => {
                set((state) => {
                    state.humans = state.humans.filter(h => h.modelUuid !== modelUuid);
                });
            },

            updateHuman: (modelUuid, updates) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        Object.assign(human, updates);
                    }
                });
            },

            clearHumans: () => {
                set((state) => {
                    state.humans = [];
                });
            },

            setCurrentPhase: (modelUuid, phase) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.currentPhase = phase;
                    }
                });
            },

            addCurrentAction: (modelUuid, actionUuid) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        const action = human.point.actions.find(h => h.actionUuid === actionUuid);
                        if (action) {
                            human.currentAction = {
                                actionUuid: action.actionUuid,
                                actionName: action.actionName
                            };
                        }
                    }
                });
            },

            removeCurrentAction: (modelUuid) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.currentAction = undefined;
                    }
                });
            },

            setHumanActive: (modelUuid, isActive) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.isActive = isActive;
                    }
                });
            },

            setHumanScheduled: (modelUuid, isScheduled) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.isScheduled = isScheduled;
                    }
                });
            },

            setHumanLoad: (modelUuid, load) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.currentLoad = load;
                    }
                });
            },

            setHumanState: (modelUuid, newState) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.state = newState;
                    }
                });
            },

            incrementHumanLoad: (modelUuid, incrementBy) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.currentLoad += incrementBy;
                    }
                });
            },

            decrementHumanLoad: (modelUuid, decrementBy) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.currentLoad -= decrementBy;
                    }
                });
            },

            addCurrentMaterial: (modelUuid, materialType, materialId) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.currentMaterials.push({ materialType, materialId });
                    }
                });
            },

            setCurrentMaterials: (modelUuid, materials) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.currentMaterials = materials;
                    }
                });
            },

            removeLastMaterial: (modelUuid) => {
                let removed;
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human && human.currentMaterials.length > 0) {
                        removed = JSON.parse(JSON.stringify(human.currentMaterials.pop()));
                    }
                });
                return removed;
            },

            getLastMaterial: (modelUuid) => {
                const human = get().humans.find(h => h.modelUuid === modelUuid);
                if (human && human.currentMaterials.length > 0) {
                    return human.currentMaterials[human.currentMaterials.length - 1];
                }
                return undefined;
            },

            clearCurrentMaterials: (modelUuid) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.currentMaterials = [];
                    }
                });
            },

            incrementActiveTime: (modelUuid, incrementBy) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.activeTime += incrementBy;
                    }
                });
            },

            incrementIdleTime: (modelUuid, incrementBy) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.idleTime += incrementBy;
                    }
                });
            },

            incrementDistanceTraveled: (modelUuid, incrementBy) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.distanceTraveled += incrementBy;
                    }
                });
            },

            resetTime: (modelUuid) => {
                set((state) => {
                    const human = state.humans.find(h => h.modelUuid === modelUuid);
                    if (human) {
                        human.activeTime = 0;
                        human.idleTime = 0;
                    }
                });
            },

            getHumanById: (modelUuid) => {
                return get().humans.find(h => h.modelUuid === modelUuid);
            },

            getHumansByProduct: (productUuid) => {
                return get().humans.filter(h => h.productUuid === productUuid);
            },

            getActiveHumans: () => {
                return get().humans.filter(h => h.isActive);
            }
        }))
    );
};

export type HumanStoreType = ReturnType<typeof createHumanStore>;
