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

interface WallStore {
    walls: Wall[];
    setWalls: (walls: Wall[]) => void;
    addWall: (wall: Wall) => void;
    updateWall: (uuid: string, updated: Partial<Wall>) => void;
    removeWall: (uuid: string) => void;
    addDecal: (wallUuid: string, decal: Decal) => void;
    updateDecal: (decalUuid: string, decal: Decal) => void;
    removeDecal: (decalUuid: string) => void;
    updateDecalPosition: (decalUuid: string, position: [number, number, number]) => void;
    updateDecalRotation: (decalUuid: string, rotation: number) => void;
    updateDecalScale: (decalUuid: string, scale: number) => void;

    removePoint: (pointUuid: string) => Wall[];
    setPosition: (pointUuid: string, position: [number, number, number]) => void;
    setLayer: (pointUuid: string, layer: number) => void;

    getWallById: (uuid: string) => Wall | undefined;
    getWallByPointId: (uuid: string) => Wall | undefined;
    getWallByPoints: (points: Point[]) => Wall | undefined;
    getWallPointById: (uuid: string) => Point | undefined;
    getConnectedPoints: (uuid: string) => Point[];
}

export const useWallStore = create<WallStore>()(
    immer((set, get) => ({
        walls: [],

        setWalls: (walls) => set((state) => {
            state.walls = walls;
        }),

        addWall: (wall) => set((state) => {
            state.walls.push(wall);
        }),

        updateWall: (uuid, updated) => set((state) => {
            const wall = state.walls.find(w => w.wallUuid === uuid);
            if (wall) {
                Object.assign(wall, updated);
            }
        }),

        removeWall: (uuid) => set((state) => {
            state.walls = state.walls.filter(w => w.wallUuid !== uuid);
        }),

        addDecal: (wallUuid, decal) => set((state) => {
            const wallToUpdate = state.walls.find(w => w.wallUuid === wallUuid);
            if (wallToUpdate) {
                wallToUpdate.decals.push(decal);
            }
        }),

        updateDecal: (decalUuid, decal) => set((state) => {
            for (const wall of state.walls) {
                const decalToUpdate = wall.decals.find(d => d.decalUuid === decalUuid);
                if (decalToUpdate) {
                    Object.assign(decalToUpdate, decal);
                }
            }
        }),

        removeDecal: (decalUuid) => set((state) => {
            for (const wall of state.walls) {
                wall.decals = wall.decals.filter(d => d.decalUuid !== decalUuid);
            }
        }),

        updateDecalPosition: (decalUuid, position) => set((state) => {
            for (const wall of state.walls) {
                const decal = wall.decals.find(d => d.decalUuid === decalUuid);
                if (decal) {
                    decal.decalPosition = position;
                    break;
                }
            }
        }),

        updateDecalRotation: (decalUuid, rotation) => set((state) => {
            for (const wall of state.walls) {
                const decal = wall.decals.find(d => d.decalUuid === decalUuid);
                if (decal) {
                    decal.decalRotation = rotation;
                    break;
                }
            }
        }),

        updateDecalScale: (decalUuid, scale) => set((state) => {
            for (const wall of state.walls) {
                const decal = wall.decals.find(d => d.decalUuid === decalUuid);
                if (decal) {
                    decal.decalScale = scale;
                    break;
                }
            }
        }),

        removePoint: (pointUuid) => {
            const removedWalls: Wall[] = [];
            set((state) => {
                state.walls = state.walls.filter((wall) => {
                    const hasPoint = wall.points.some(p => p.pointUuid === pointUuid);
                    if (hasPoint) {
                        removedWalls.push(JSON.parse(JSON.stringify(wall)));
                        return false;
                    }
                    return true;
                });
            });
            return removedWalls;
        },

        setPosition: (pointUuid, position) => set((state) => {
            for (const wall of state.walls) {
                const point = wall.points.find(p => p.pointUuid === pointUuid);
                if (point) {
                    point.position = position;
                }
            }
        }),

        setLayer: (pointUuid, layer) => set((state) => {
            for (const wall of state.walls) {
                const point = wall.points.find(p => p.pointUuid === pointUuid);
                if (point) {
                    point.layer = layer;
                }
            }
        }),

        getWallById: (uuid) => {
            return get().walls.find(w => w.wallUuid === uuid);
        },

        getWallByPointId: (uuid) => {
            for (const wall of get().walls) {
                if (wall.points.some(p => p.pointUuid === uuid)) {
                    return wall;
                }
            }
            return undefined;
        },

        getWallByPoints: (point) => {
            for (const wall of get().walls) {
                if (((wall.points[0].pointUuid === point[0].pointUuid) || (wall.points[1].pointUuid === point[0].pointUuid)) &&
                    ((wall.points[0].pointUuid === point[1].pointUuid) || (wall.points[1].pointUuid === point[1].pointUuid))) {
                    return wall;
                }
            }
            return undefined;
        },

        getWallPointById: (uuid) => {
            for (const wall of get().walls) {
                const point = wall.points.find(p => p.pointUuid === uuid);
                if (point) return point;
            }
            return undefined;
        },

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