import React, { useState, useEffect } from "react";
import {
  View,
  PanResponder,
  Text,
  TouchableOpacity,
  Animated,
  Dimensions,
} from "react-native";
import UniCameraHandler from "./UniCameraHandler";
import ExpoTHREE from "expo-three";
global.Image = undefined;
import ExpoGraphics from "expo-graphics";
import * as THREE from "three";
import { connect } from "react-redux";
import actions from "../../actions";
import {
  getVerticesWithText,
  addShapes,
  removeShapes,
  loadSavedState,
} from "../../components/helper/ShapeHelper";
import {
  addPoints,
  removePoints,
  connectPoints,
  disconnectPoints,
} from "../../components/helper/PointHelper";
import Toast from "react-native-toast-message";
//import DragControls from "../../components/helper/DragControls";
import { formatDateTime } from "../../components/helper/DatabaseHelper";
const mapDispatchToProps = (dispatch) => {
  return {
    reduxSetBasicComponents: (components) => {
      dispatch(actions.setCamera(components.camera));
      dispatch(actions.setCameraHandler(components.cameraHandler));
      dispatch(actions.setRenderer(components.renderer));
      dispatch(actions.setScene(components.scene));
    },
    reduxSetPoint: (points) => {
      dispatch(actions.setPoints(points));
    },
    reduxAddLine: (line) => {
      dispatch(actions.addLine(line));
    },
    reduxRemoveLine: (line) => {
      dispatch(actions.removeLine(line));
    },
    reduxSetLine: (lines) => {
      dispatch(actions.setLines(lines));
    },
    reduxAddShape: (shape) => {
      dispatch(actions.addShape(shape));
    },
    reduxRemoveShape: (shape) => {
      dispatch(actions.removeShape(shape));
    },
    reduxSetShape: (shapes) => {
      dispatch(actions.setShapes(shapes));
    },
    reduxAddSaveItem: (item) => {
      dispatch(actions.addSaveItem(item));
    },
    reduxSetSaveItem: (items) => {
      dispatch(actions.setSaveItem(items));
    },
    reduxSetDisableCamera: (isDisabled) => {
      dispatch(actions.setDisableCamera(isDisabled));
    },
    /*reduxSetControls: (controls) => {
      dispatch(actions.setControls(controls));
    },*/
  };
};
const mapStateToProps = (state) => {
  return {
    basicComponents: state.basicComponents,
    saveComponents: state.saveComponents,
    miscData: state.miscData,
  };
};
const { height, width } = Dimensions.get("window");

export default connect(mapStateToProps, mapDispatchToProps)(LayoutSetup);
function LayoutSetup(props) {
  const raw_font = require("../../assets/fonts/bebas_neue.typeface.json");
  const font = new THREE.Font(raw_font);
  const [pan, setPan] = useState(new Animated.ValueXY());
  const [mouse, setMouse] = useState(new THREE.Vector2(-10, -10));
  const [val, setVal] = useState({ x: 0, y: 0 });
  const [isLock, setIsLock] = useState(false);
  const _transformEvent = (event) => {
    event.preventDefault = event.preventDefault || (() => {});
    event.stopPropagation = event.stopPropagation || (() => {});
    return event;
  };

  //Should we become active when the user presses down on the square?
  const handleStartShouldSetPanResponder = () => {
    return true;
  };

  // We were granted responder status! Let's update the UI
  const handlePanResponderGrant = (e, gestureState) => {
    const event = _transformEvent({ ...e, gestureState });
    const disableCamera = props.miscData.disableCamera;
    if (disableCamera) {
      pan.setOffset({
        x: val.x,
        y: val.y,
      });
      pan.setValue({ x: -10, y: -10 });
      mouse.x = (event.nativeEvent.pageX / width) * 2 - 1;
      mouse.y = -(event.nativeEvent.pageY / height) * 2 + 1;
      //props.basicComponents.controls.onDocumentTouchStart(mouse);
    }
    if (!disableCamera)
      props.basicComponents.cameraHandler.handlePanResponderGrant(
        event.nativeEvent
      );
  };

  // Every time the touch/mouse moves
  const handlePanResponderMove = (e, gestureState) => {
    // Keep track of how far we've moved in total (dx and dy)
    const event = _transformEvent({ ...e, gestureState });
    const disableCamera = props.miscData.disableCamera;
    if (disableCamera) {
      mouse.x = (event.nativeEvent.pageX / width) * 2 - 1;
      mouse.y = -(event.nativeEvent.pageY / height) * 2 + 1;
      //props.basicComponents.controls.onDocumentMouseMove(mouse);
    }
    if (!disableCamera)
      props.basicComponents.cameraHandler.handlePanResponderMove(
        event.nativeEvent,
        gestureState
      );
  };

  // When the touch/mouse is lifted
  const handlePanResponderEnd = (e, gestureState) => {
    const event = _transformEvent({ ...e, gestureState });
    //clearTimeout(longPressTimeout);
    const disableCamera = props.miscData.disableCamera;
    if (disableCamera) {
      mouse.x = -10;
      mouse.y = -10;
      //props.basicComponents.controls.onDocumentMouseCancel();
    }
    if (!disableCamera)
      props.basicComponents.cameraHandler.handlePanResponderEnd(
        event.nativeEvent
      );
  };

  pan.addListener((value) => setVal(() => value));
  const panResponder = PanResponder.create({
    onStartShouldSetPanResponder: handleStartShouldSetPanResponder,
    onPanResponderGrant: handlePanResponderGrant,
    onPanResponderMove: handlePanResponderMove,
    onPanResponderRelease: handlePanResponderEnd,
    onPanResponderTerminate: handlePanResponderEnd,
    onShouldBlockNativeResponder: () => false,
    onPanResponderTerminationRequest: () => true,
  });
  const updatePoints = () => {
    if (props.basicComponents.points != null) {
      props.getPointsCallback(
        props.basicComponents.points.map((item) => {
          return {
            point: item.position,
            text: item.trueText,
            item: item,
          };
        })
      );
    }
  }; //, [props.basicComponents.points]);
  const loadFont = (listOfVertices) => {
    let listOfObjects = [];
    for (let item of listOfVertices) {
      const vertex = item.point;
      const textGeo = new THREE.TextGeometry(item.text, {
        font: font,
        size: 0.5,
        height: 0.01,
      });

      let textMaterial = new THREE.MeshBasicMaterial({
        color: 0xffffff,
      });
      let text = new THREE.Mesh(textGeo, textMaterial);
      props.basicComponents.scene.add(text);
      text.position.set(vertex.x, vertex.y, vertex.z);
      text.quaternion.copy(props.basicComponents.camera.quaternion);

      let point = {
        text: text,
        position: vertex,
        trueText: item.text,
      };
      listOfObjects.push(point);
    }
    let holder =
      props.basicComponents.points == null ? [] : props.basicComponents.points;
    props.reduxSetPoint([...listOfObjects, ...holder]);
    updatePoints();
    return listOfObjects;
  };

  const onContextCreate = ({ gl, width, height, scale }) => {
    if (props.basicComponents.scene) props.basicComponents.scene.dispose();

    props.reduxSetPoint([]);
    props.reduxSetLine([]);
    props.reduxSetShape([]);
    props.reduxSetDisableCamera(false);
    //props.reduxSetControls(null);

    let renderer = new ExpoTHREE.Renderer({ gl });
    renderer.setPixelRatio(scale);
    renderer.setSize(width, height);
    renderer.setClearColor(0x000000, 1.0);
    //console.log(renderer.domElement)

    let scene = new THREE.Scene();
    let camera = new THREE.PerspectiveCamera(100, width / height, 0.1, 1000);
    //grid size = 2pixel
    let geometry = null;
    switch (props.initShape) {
      case "cube": {
        geometry = new THREE.BoxBufferGeometry(5, 5, 5);
        //numVertices = 8
        break;
      }
      case "cone": {
        geometry = new THREE.ConeBufferGeometry(5, 10, 32);
        //numVertices = 1
        break;
      }
      case "sphere": {
        geometry = new THREE.SphereBufferGeometry(5, 20, 20);
        //numVertices = 1
        break;
      }
      case "octahedron": {
        geometry = new THREE.OctahedronBufferGeometry(5, 0);
        //numVertices = 6
        break;
      }
      case "prism": {
        geometry = new THREE.CylinderBufferGeometry(5, 5, 10, 3);
        break;
      }
      default: {
        if (props.savedState) {
          loadSavedState(props, scene, updatePoints);
        }
        break;
      }
    }

    const material = new THREE.MeshBasicMaterial({
      color: 0xe7ff37,
      opacity: 0.5,
      transparent: true,
      side: THREE.DoubleSide,
    });
    const axisHelper = new THREE.AxesHelper(200);
    const cameraHandler = new UniCameraHandler(camera);
    props.getCam(cameraHandler);
    const plane = new THREE.GridHelper(200, 200, "#ff3700");

    scene.add(plane, axisHelper);
    props.reduxSetBasicComponents({
      camera: camera,
      cameraHandler: cameraHandler,
      scene: scene,
      renderer: renderer,
    });

    if (geometry) {
      let mesh = new THREE.Mesh(geometry, material);
      let edges = new THREE.EdgesGeometry(geometry);
      let line = new THREE.LineSegments(
        edges,
        new THREE.LineBasicMaterial({ color: 0xffffff })
      );
      //let wrapper = new THREE.Object3D();
      //wrapper.add(mesh, line);
      scene.add(mesh, line);

      const holder = loadFont(getVerticesWithText(mesh, props.initShape));
      //console.log(holder)
      props.reduxSetShape([
        {
          object: mesh,
          edges: line,
          color: "#e7ff37",
          name: "default",
          type: props.initShape,
          id: 0,
          position: new THREE.Vector3(0, 0, 0),
          rotation: new THREE.Vector3(0, 0, 0),
          points: holder,
        },
      ]);
      props.getShapesCallback(props.basicComponents.shapes);
    }
  };

  const onRender = (delta) => {
    props.basicComponents.cameraHandler.render(props.basicComponents.points);
    props.basicComponents.renderer.render(
      props.basicComponents.scene,
      props.basicComponents.camera
    );
  };

  useEffect(() => {
    if (props.pointsEdit && props.pointsEdit.length > 0) {
      switch (props.action) {
        case "add_points": {
          addPoints(loadFont, props.pointsEdit);
          break;
        }
        case "remove_points": {
          removePoints(props, updatePoints, props.pointsEdit);
          break;
        }
        default: {
          break;
        }
      }
    }
  }, [props.signalEditPoints]);
  useEffect(() => {
    if (props.pointsConnect && props.pointsConnect.length > 0) {
      switch (props.action) {
        case "connect_points": {
          connectPoints(props, loadFont, props.pointsConnect);
          break;
        }
        case "disconnect_points": {
          disconnectPoints(props, props.pointsConnect);
          break;
        }
        default: {
          break;
        }
      }
    }
  }, [props.signalPoints]);

  useEffect(() => {
    if (props.shapesConnect && props.shapesConnect.length > 0) {
      switch (props.action) {
        case "add_shapes": {
          addShapes(props, props.shapesConnect, updatePoints);
          break;
        }
        case "remove_shapes": {
          removeShapes(props, props.shapesConnect);
          break;
        }
        default: {
          break;
        }
      }
    }
  }, [props.signalShapes]);

  return (
    <>
      <View
        {...panResponder.panHandlers}
        style={{
          flex: 1,
          overflow: "hidden",
          width: "100%",
          height: "100%",
        }}
      >
        <ExpoGraphics.View
          style={{ flex: 1 }}
          onContextCreate={(props) => {
            onContextCreate(props);
          }}
          onRender={(_props) => onRender(_props)}
          arEnabled={false}
          onShouldReloadContext={() => true}
        />
      </View>
      <TouchableOpacity
        style={{
          backgroundColor: "black",
          top: 20,
          right: 90,
          position: "absolute",
          paddingVertical: 5,
          paddingHorizontal: 10,
          borderRadius: 5,
          borderColor: "red",
          borderWidth: 2,
        }}
        onPress={() => {
          props.reduxSetDisableCamera(!props.miscData.disableCamera);
          setIsLock(() => !isLock);
        }}
      >
        <Text
          style={{
            color: "red",
          }}
        >
          {isLock ? "Unlock" : "Lock"}
        </Text>
      </TouchableOpacity>
      <TouchableOpacity
        style={{
          backgroundColor: "black",
          top: 20,
          right: 20,
          position: "absolute",
          paddingVertical: 5,
          paddingHorizontal: 10,
          borderRadius: 5,
          borderColor: "white",
          borderWidth: 2,
        }}
        onPress={() => {
          const currentItem = {
            shapes: props.basicComponents.shapes,
            lines: props.basicComponents.lines,
            points: props.basicComponents.points,
            name: formatDateTime(new Date()),
            fileName: Date.now(),
            isSynced: false,
            url: "",
          };
          props.reduxAddSaveItem(currentItem);
          Toast.show({
            type: "success",
            position: "top",
            text1: "Current state saved",
            text2: "Success",
            visibilityTime: 3000,
            autoHide: true,
          });
        }}
      >
        <Text
          style={{
            color: "white",
          }}
        >
          Save
        </Text>
      </TouchableOpacity>
    </>
  );
}