import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

export default class ThreeConduit {
  dataList = [];
  diffNumber = 0;
  threeDom;
  scene;
  camera;
  renderer;
  controls;
  constructor(threeDom, dataList, diffNumber) {
    this.threeDom = threeDom;
    this.dataList = dataList;
    this.diffNumber = diffNumber;
    // 场景
    this.scene = new THREE.Scene();

    // 相机
    this.camera = new THREE.PerspectiveCamera(
      75,
      window.innerWidth / window.innerHeight,
      0.1,
      1000
    );
    // 渲染器
    this.renderer = new THREE.WebGLRenderer();
    if (threeDom) {
      threeDom.appendChild(this.renderer.domElement);
      this.renderer.setSize(threeDom.offsetWidth, threeDom.offsetHeight);
    } else {
      document.body.appendChild(this.renderer.domElement);
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    }

    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
  }
  init() {
    let data = this.dataList;
    if (this.diffNumber > 0) {
      for (let i = 0; i < this.diffNumber; i++) {
        data = this.surfaceFunction(data);
      }
    }

    let container = [];
    const colors = [];
    let height = 50;
    for (let i = 0; i < data.length; i++) {
      let list = [];
      for (let j = 0; j < data[i].length; j++) {
        let angle = (j * Math.PI * 2) / data[i].length;
        let x = Math.cos(angle) * data[i][j];
        let y = Math.sin(angle) * data[i][j];
        list.push([x, y, height * i, data[i][j]]);
      }
      container.push(list);
    }

    const geometry = new THREE.BufferGeometry();

    const vertices = [];
    for (let i = 0; i < container.length - 1; i++) {
      for (let j = 0; j < container[i].length; j++) {
        vertices.push(
          container[i][j][0],
          container[i][j][1],
          container[i][j][2]
        );
        colors.push(...this.valueToColor((container[i][j][3] - 32 + 10) / 20));
        if (j + 1 == container[i].length) {
          vertices.push(
            container[i][0][0],
            container[i][0][1],
            container[i][0][2]
          );
          colors.push(
            ...this.valueToColor((container[i][0][3] - 32 + 10) / 20)
          );
        } else {
          vertices.push(
            container[i][j + 1][0],
            container[i][j + 1][1],
            container[i][j + 1][2]
          );
          colors.push(
            ...this.valueToColor((container[i][j + 1][3] - 32 + 10) / 20)
          );
        }
        vertices.push(
          container[i + 1][j][0],
          container[i + 1][j][1],
          container[i + 1][j][2]
        );
        colors.push(
          ...this.valueToColor((container[i + 1][j][3] - 32 + 10) / 20)
        );
        if (j + 1 == container[i].length) {
          vertices.push(
            container[i][0][0],
            container[i][0][1],
            container[i][0][2]
          );
          colors.push(
            ...this.valueToColor((container[i][0][3] - 32 + 10) / 20)
          );
        } else {
          vertices.push(
            container[i][j + 1][0],
            container[i][j + 1][1],
            container[i][j + 1][2]
          );
          colors.push(
            ...this.valueToColor((container[i][j + 1][3] - 32 + 10) / 20)
          );
        }
        vertices.push(
          container[i + 1][j][0],
          container[i + 1][j][1],
          container[i + 1][j][2]
        );
        colors.push(
          ...this.valueToColor((container[i + 1][j][3] - 32 + 10) / 20)
        );
        if (j + 1 == container[i].length) {
          vertices.push(
            container[i + 1][0][0],
            container[i + 1][0][1],
            container[i + 1][0][2]
          );
          colors.push(
            ...this.valueToColor((container[i + 1][0][3] - 32 + 10) / 20)
          );
        } else {
          vertices.push(
            container[i + 1][j + 1][0],
            container[i + 1][j + 1][1],
            container[i + 1][j + 1][2]
          );
          colors.push(
            ...this.valueToColor((container[i + 1][j + 1][3] - 32 + 10) / 20)
          );
        }
      }
    }

    // itemSize = 3 因为每个顶点都是一个三元组。
    geometry.setAttribute(
      "position",
      new THREE.BufferAttribute(new Float32Array(vertices), 3)
    );
    geometry.setAttribute(
      "color",
      new THREE.BufferAttribute(new Float32Array(colors), 3)
    );
    // 顶点着色器代码
    const vertexShader = `
varying vec3 vPosition;//表示顶点插值后位置数据，与片元数量相同，一一对应
varying vec3 vColor;// varying关键字声明一个变量表示顶点颜色插值后的结果
void main(){
  vColor = color;// 顶点颜色数据进行插值计算
  vPosition = position;// 顶点位置坐标插值计算
  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`;

    // 片元着色器代码
    // const fragmentShader = `
    // varying vec3 vPosition;//获取顶点着色器插值数据vPosition
    // void main() {
    //   // 根据vPosition位置控制片元颜色
    //   float val = vPosition.x*vPosition.x + vPosition.y*vPosition.y;
    //   float base = 32.0*32.0;
    //   float per = (val-base) /1000.0;
    //   gl_FragColor = vec4(per,1.0-per,0.0,1.0);
    // }`;
    const fragmentShader = `
varying vec3 vColor;// 顶点片元化后有多少个片元,顶点颜色插值后就有多少个颜色数据
void main() {
    gl_FragColor = vec4(vColor,1.0);
}
`;

    const material = new THREE.ShaderMaterial({
      vertexShader: vertexShader,
      fragmentShader: fragmentShader,
      side: THREE.DoubleSide,
      vertexColors: true,
    });
    const materialLine = new THREE.LineBasicMaterial({
      color: "#000",
    });
    // const material = new THREE.MeshBasicMaterial({
    //   color: "#4DFFB1",
    //   side: THREE.DoubleSide,
    //   wireframe:false
    // });
    const mesh = new THREE.Mesh(geometry, material);
    this.scene.add(mesh);

    let surfaceWire = new THREE.WireframeGeometry(geometry);
    let lineWire = new THREE.LineSegments(surfaceWire, materialLine);
    this.scene.add(lineWire);
    const axesHelper = new THREE.AxesHelper(100);
    this.scene.add(axesHelper);

    // controls.addEventListener('change',animate);

    // 设置相机位置并指向场景中心
    this.camera.position.z = 500;
    this.animate();
    // 监听鼠标按下事件
    document.addEventListener("keydown", (event) => {
      const dir = new THREE.Vector3();
      // 获取相机的视线方向
      this.camera.getWorldDirection(dir);
      // dis向量表示相机沿着相机视线方向平移200的位移量
      let dis = dir.clone();
      switch (event.code) {
        case "KeyA":
          // console.log('A');
          break;
        case "KeyS":
          dis = dir.clone().multiplyScalar(-5);
          this.camera.position.add(dis);
          break;
        case "KeyD":
          // console.log('D');
          break;
        case "KeyW":
          dis = dir.clone().multiplyScalar(5);
          this.camera.position.add(dis);
          break;
      }
      this.animate();
    });
  }

  animate() {
    requestAnimationFrame(this.animate.bind(this));
    this.controls.update();
    this.renderer.render(this.scene, this.camera);
  }

  surfaceFunction(data) {
    let container = [];
    for (let i = 0; i < data.length; i++) {
      let list = [];
      for (let j = 0; j < data[i].length; j++) {
        list.push(data[i][j]);

        list.push(
          (data[i][j + 1 == data[i].length ? 0 : j + 1] + data[i][j]) / 2
        );
      }
      container.push(list);
    }

    return container;
  }

  valueToColor(value) {
    // 将最小颜色和最大颜色转换为RGB
    let minColor = parseInt("0x0000ff", 16);
    let maxColor = parseInt("0x00ff00", 16);
    if (value > 0.5) {
      minColor = parseInt("0x00ff00", 16);
      maxColor = parseInt("0xff0000", 16);
    }
    // 将颜色组件分离成单独的值
    let minR = (minColor >> 16) & 0xff;
    let minG = (minColor >> 8) & 0xff;
    let minB = minColor & 0xff;

    let maxR = (maxColor >> 16) & 0xff;
    let maxG = (maxColor >> 8) & 0xff;
    let maxB = maxColor & 0xff;

    // 进行线性插值
    let r = Math.round(minR + (maxR - minR) * value);
    let g = Math.round(minG + (maxG - minG) * value);
    let b = Math.round(minB + (maxB - minB) * value);

    // 将RGB转换回16进制颜色
    return [r / 255, g / 255, b / 255];
  }
}
