import React, { useEffect, useMemo } from "react";
import { DoubleSide, RepeatWrapping, SRGBColorSpace, TextureLoader, Vector2, Vector3 } from "three";
import { Html } from "@react-three/drei";
import { useLoader } from "@react-three/fiber";
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
import { useSceneContext } from "../../../scene/sceneContext";
import { useToggleView, useToolMode } from "../../../../store/builder/store";
import { useWallClassification } from "./instance/helpers/useWallClassification";
import Line from "../../line/line";
import Point from "../../point/point";
import WallInstance from "./instance/wallInstance";
import * as Constants from "../../../../types/world/worldConstants";

import texturePath from "../../../../assets/textures/floor/white.png";
import texturePathDark from "../../../../assets/textures/floor/black.png";
import useModuleStore from "../../../../store/ui/useModuleStore";
import getCenteroidPoint from "../../functions/getCenteroid";
import getArea from "../../functions/getArea";
import ExtrudePolygon from "../../wrappers/geomentry/extrudePolygon";

function WallInstances() {
    const { wallStore } = useSceneContext();
    const { setSelectedWall, selectedWall } = useBuilderStore();
    const { toolMode } = useToolMode();
    const { toggleView } = useToggleView();
    const { activeModule } = useModuleStore();
    const { walls } = wallStore();
    const { rooms } = useWallClassification(walls);

    useEffect(() => {
        // console.log("walls: ", walls);
    }, [walls]);

    useEffect(() => {
        if (!toggleView && activeModule === "builder") {
            if (toolMode !== "cursor") {
                if (selectedWall) setSelectedWall(null);
            }
        } else {
            if (selectedWall) setSelectedWall(null);
        }
    }, [toggleView, toolMode, activeModule, selectedWall]);

    const allPoints = useMemo(() => {
        const points: Point[] = [];
        const seenUuids = new Set<string>();

        walls.forEach((wall) => {
            wall.points.forEach((point) => {
                if (!seenUuids.has(point.pointUuid)) {
                    seenUuids.add(point.pointUuid);
                    points.push(point);
                }
            });
        });

        return points;
    }, [walls]);

    return (
        <>
            {!toggleView && (
                <>
                    {walls.map((wall) => (
                        <WallInstance key={wall.wallUuid} wall={wall} />
                    ))}

                    <group name="Wall-Floors-Group">
                        {rooms.map((room, index) => (
                            <Floor3D key={index} room={room} />
                        ))}
                    </group>
                </>
            )}

            {toggleView && (
                <>
                    <group name="Wall-Points-Group">
                        {allPoints.map((point) => (
                            <Point key={point.pointUuid} point={point} />
                        ))}
                    </group>

                    <group name="Wall-Floors-Group">
                        {rooms.map((room, index) => (
                            <Floor2D key={index} room={room} />
                        ))}
                    </group>

                    <group name="Wall-Lines-Group">
                        {walls.map((wall) => (
                            <React.Fragment key={wall.wallUuid}>
                                <Line points={wall.points} />
                            </React.Fragment>
                        ))}

                        {walls.map((wall) => {
                            const textPosition = new Vector3().addVectors(new Vector3(...wall.points[0].position), new Vector3(...wall.points[1].position)).divideScalar(2);
                            const distance = new Vector3(...wall.points[0].position).distanceTo(new Vector3(...wall.points[1].position));

                            return (
                                <React.Fragment key={wall.wallUuid}>
                                    {toggleView && (
                                        <Html
                                            key={`${wall.points[0].pointUuid}_${wall.points[1].pointUuid}`}
                                            userData={wall}
                                            position={[textPosition.x, 1, textPosition.z]}
                                            wrapperClass="distance-text-wrapper"
                                            className="distance-text"
                                            zIndexRange={[1, 0]}
                                            prepend
                                            sprite
                                        >
                                            <div key={wall.wallUuid} className={`distance ${wall.wallUuid}`}>
                                                {distance.toFixed(2)} m
                                            </div>
                                        </Html>
                                    )}
                                </React.Fragment>
                            );
                        })}
                    </group>
                </>
            )}
        </>
    );
}

export default WallInstances;

function Floor3D({ room }: { readonly room: Point[] }) {
    const savedTheme: string | null = localStorage.getItem("theme");
    const textureScale = Constants.floorConfig.textureScale;
    const floorTexture = useLoader(TextureLoader, savedTheme === "dark" ? texturePathDark : texturePath);
    floorTexture.wrapS = floorTexture.wrapT = RepeatWrapping;
    floorTexture.repeat.set(textureScale, textureScale);
    floorTexture.colorSpace = SRGBColorSpace;

    return (
        <ExtrudePolygon points={room} receiveShadow castShadow name="Wall-Floor" options={{ depth: Constants.floorConfig.height, bevelEnabled: false }}>
            <meshStandardMaterial color={Constants.floorConfig.defaultColor} map={floorTexture} side={DoubleSide} />
        </ExtrudePolygon>
    );
}

function Floor2D({ room }: { readonly room: Point[] }) {
    const savedTheme: string | null = localStorage.getItem("theme");

    const points2D = useMemo(() => {
        return room.map((p) => new Vector2(parseFloat(p.position[0].toFixed(2)), parseFloat(p.position[2].toFixed(2))));
    }, [room]);

    const area = useMemo(() => getArea(points2D), [points2D]);

    const centroid: [number, number, number] = useMemo(() => {
        const center = getCenteroidPoint(points2D);
        if (!center) return [0, Constants.floorConfig.height, 0];

        return [center.x, Constants.floorConfig.height, center.y] as [number, number, number];
    }, [points2D]);

    const formattedArea = `${area.toFixed(2)} m²`;

    return (
        <>
            <ExtrudePolygon points={room} receiveShadow castShadow name="Wall-Floor" position={[0, 0.05, 0]} options={{ depth: 0, bevelEnabled: false }}>
                <meshBasicMaterial color={savedTheme === "dark" ? Constants.lineConfig.wallColor : Constants.lineConfig.wallColor} side={DoubleSide} transparent opacity={0.4} depthWrite={false} />
            </ExtrudePolygon>

            <Html position={centroid} wrapperClass="distance-text-wrapper" className="distance-text" zIndexRange={[1, 0]} prepend center sprite>
                <div className="distance area">({formattedArea})</div>
            </Html>
        </>
    );
}
