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

type MaterialsStore = {
    materials: MaterialsSchema;
    materialHistory: MaterialHistorySchema;

    addMaterial: (material: MaterialSchema) => MaterialSchema | undefined;
    removeMaterial: (materialId: string) => MaterialSchema | undefined;
    clearMaterials: () => void;
    updateMaterial: (materialId: string, updates: Partial<MaterialSchema>) => MaterialSchema | undefined;

    setPreviousLocation: (
        materialId: string,
        location: {
            modelUuid: string;
            pointUuid: string;
            actionUuid: string;
        }
    ) => MaterialSchema | undefined;

    setCurrentLocation: (
        materialId: string,
        location: {
            modelUuid: string;
            pointUuid: string;
            actionUuid: string;
        }
    ) => MaterialSchema | undefined;

    setNextLocation: (
        materialId: string,
        location: {
            modelUuid: string;
            pointUuid: string;
        } | null
    ) => MaterialSchema | undefined;

    clearLocations: (materialId: string) => void;

    setMaterial: (materialId: string, materialType: string) => MaterialSchema | undefined;
    setStartTime: (materialId: string, startTime: number) => MaterialSchema | undefined;
    setEndTime: (materialId: string, endTime: number) => MaterialSchema | undefined;
    setCost: (materialId: string, cost: number) => MaterialSchema | undefined;
    setWeight: (materialId: string, weight: number) => MaterialSchema | undefined;
    setIsActive: (materialId: string, isActive: boolean) => MaterialSchema | undefined;
    setIsVisible: (materialId: string, isVisible: boolean) => MaterialSchema | undefined;
    setIsPaused: (materialId: string, isPaused: boolean) => MaterialSchema | undefined;
    setIsRendered: (materialId: string, isRendered: boolean) => MaterialSchema | undefined;

    getMaterialById: (materialId: string) => MaterialSchema | undefined;
    getMaterialsByCurrentModelUuid: (currentModelUuid: string) => MaterialSchema[] | undefined;
    getMaterialByCurrentPointUuid: (currentPointUuid: string) => MaterialSchema | undefined;
    getMaterialsByPoint: (pointUuid: string) => MaterialSchema[];
    getMaterialsByModel: (modelUuid: string) => MaterialSchema[];
    getMaterialHistory: () => MaterialHistorySchema;
};

export const createMaterialStore = () => {
    return create<MaterialsStore>()(
        immer((set, get) => ({
            materials: [],
            materialHistory: [],

            addMaterial: (material) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    state.materials.push(material);
                });
                return updatedMaterial;
            },

            removeMaterial: (materialId) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        state.materials = state.materials.filter(m => m.materialId !== materialId);
                        updatedMaterial = JSON.parse(JSON.stringify(material));

                        state.materialHistory.push({
                            material,
                            removedAt: new Date().toISOString()
                        });
                    }
                });
                return updatedMaterial;
            },

            clearMaterials: () => {
                set((state) => {
                    state.materials = [];
                    state.materialHistory = [];
                });
            },

            updateMaterial: (materialId, updates) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        Object.assign(material, updates);
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    }
                });
                return updatedMaterial;
            },

            setPreviousLocation: (materialId, location) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.previous = location;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    }
                });
                return updatedMaterial;
            },

            setCurrentLocation: (materialId, location) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.current = location;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    }
                });
                return updatedMaterial;
            },

            setNextLocation: (materialId, location) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.next = location;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    }
                });
                return updatedMaterial;
            },

            clearLocations: (materialId) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        delete material.previous;
                        delete material.next;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    }
                });
                return updatedMaterial;
            },
            setMaterial: (materialId, materialType) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.materialType = materialType;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            setStartTime: (materialId, startTime) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.startTime = startTime
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            setEndTime: (materialId, endTime) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.endTime = endTime;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            setCost: (materialId, cost) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.cost = cost;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            setWeight: (materialId, weight) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.weight = weight;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            setIsActive: (materialId, isActive) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.isActive = isActive;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            setIsVisible: (materialId, isVisible) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.isVisible = isVisible;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            setIsPaused: (materialId, isPaused) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.isPaused = isPaused;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            setIsRendered: (materialId, isRendered) => {
                let updatedMaterial: MaterialSchema | undefined;
                set((state) => {
                    const material = state.materials.find(m => m.materialId === materialId);
                    if (material) {
                        material.isRendered = isRendered;
                        updatedMaterial = JSON.parse(JSON.stringify(material));
                    };
                });
                return updatedMaterial;
            },

            getMaterialById: (materialId) => {
                return get().materials.find(m => m.materialId === materialId);
            },

            getMaterialsByCurrentModelUuid: (currentModelUuid) => {
                return get().materials.filter(m => m.current?.modelUuid === currentModelUuid);
            },

            getMaterialByCurrentPointUuid: (currentPointlUuid) => {
                return get().materials.find(m => m.current?.pointUuid === currentPointlUuid);
            },

            getMaterialsByPoint: (pointUuid) => {
                return get().materials.filter(m =>
                    m.current?.pointUuid === pointUuid ||
                    m.next?.pointUuid === pointUuid
                );
            },

            getMaterialsByModel: (modelUuid) => {
                return get().materials.filter(m =>
                    m.current?.modelUuid === modelUuid ||
                    m.next?.modelUuid === modelUuid
                );
            },

            getMaterialHistory: () => {
                return get().materialHistory;
            },
        }))
    )
}


export type MaterialStoreType = ReturnType<typeof createMaterialStore>;