// inspiration from Etienne Jacob
// https://www.thisiscolossal.com/wp-content/uploads/2018/12/agifcolossaltd2opt.gif

import "./styles.css";
import * as THREE from "three";
// import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import vertex from "./shaders/vertex.glsl";
import fragment from "./shaders/fragment.glsl";
import txt from "./123.png";
let timer = 0;
let mouseIsDown = false;
export default class Sketch {
  constructor(options) {
    this.clock = new THREE.Clock();
    this.time = 0;
    this.container = options.domElement;
    this.height = this.container.offsetHeight;
    this.width = this.container.offsetWidth;
    this.camera = new THREE.PerspectiveCamera(
      75,
      this.width / this.height,
      0.1,
      1000
    );

    this.camera.position.set(0, 0, 10);
    this.scene = new THREE.Scene();
    this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    this.renderer.setPixelRatio(window.devicePixelRatio * 2);
    this.container.appendChild(this.renderer.domElement);
    // this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.normal = new THREE.Vector3();
    this.binormal = new THREE.Vector3();
    this.resize();
    this.addObjects();
    this.render();
    this.setUpResize();
  }

  addObjects() {
    const texture = new THREE.TextureLoader().load(txt, (texture) => {
      texture.minFilter = THREE.NearestFilter;
      texture.magFilter = THREE.NearestFilter;
    });

    this.material = new THREE.ShaderMaterial({
      side: THREE.DoubleSide,
      // transparent:true,
      // wireframe: true,
      uniforms: {
        time: { type: "f", value: 0 },
        uResolution: { type: "v4", value: new THREE.Vector4() },
        u_texture: { type: "t", value: texture }
      },
      vertexShader: vertex,
      fragmentShader: fragment
    });

    class CustomSinCurve extends THREE.Curve {
      constructor(scale = 1) {
        super();

        this.scale = scale;
      }

      getPoint(t, optionalTarget = new THREE.Vector3()) {
        const tx = Math.cos(2 * Math.PI * t);
        const ty = Math.sin(2 * Math.PI * t);
        const tz = 0.1 * Math.sin(8 * Math.PI * t);

        return optionalTarget.set(tx, ty, tz).multiplyScalar(this.scale);
      }
    }

    const path = new CustomSinCurve(10);

    this.geometry = new THREE.TubeGeometry(path, 200, 0.5, 20, false);
    this.mesh = new THREE.Mesh(this.geometry, this.material);
    this.scene.add(this.mesh);
  }

  render() {
    this.time = timer;

    // https://threejs.org/examples/webgl_geometry_extrude_splines.html
    let looptime = 10 * 1000;
    let t = (this.time % looptime) / looptime;
    let pos = this.geometry.parameters.path.getPointAt(t);
    let segments = this.geometry.tangents.length;
    let pickt = t * segments;
    let pick = Math.floor(pickt);
    let pickNext = (pick + 1) % segments;

    this.binormal.subVectors(
      this.geometry.binormals[pickNext],
      this.geometry.binormals[pick]
    );
    this.binormal
      .multiplyScalar(pickt - pick)
      .add(this.geometry.binormals[pick]);

    let dir = this.geometry.parameters.path.getTangentAt(t);
    let offset = 0;
    this.normal.copy(this.binormal).cross(dir);

    pos.add(this.normal.clone().multiplyScalar(offset));
    this.camera.position.copy(pos);

    let lookAt = this.geometry.parameters.path.getPointAt(
      (t + 1 / this.geometry.parameters.path.getLength()) % 1
    );

    this.camera.matrix.lookAt(this.camera.position, lookAt, this.normal);
    this.camera.rotation.setFromRotationMatrix(
      this.camera.matrix,
      this.camera.rotation.order
    );

    this.material.uniforms.time.value = this.clock.getElapsedTime();
    requestAnimationFrame(this.render.bind(this));

    this.renderer.render(this.scene, this.camera);
  }

  resize() {
    this.width = this.container.offsetWidth;
    this.height = this.container.offsetHeight;
    this.renderer.setSize(this.width, this.height);
    this.camera.aspect = this.width / this.height;
    this.camera.updateProjectionMatrix();
  }

  setUpResize() {
    window.addEventListener("resize", this.resize.bind(this));
  }
}

new Sketch({
  domElement: document.getElementById("container")
});

window.addEventListener("mousedown", function (e) {
  mouseIsDown = true;
});
window.addEventListener("mouseup", function (e) {
  mouseIsDown = false;
});

window.addEventListener("mousemove", function (e) {
  if (mouseIsDown) {
    timer += ((e.clientY / window.innerHeight) * 2 - 1) * 10;
  }

  if (timer <= 0) {
    timer = 0;
  }
});

setInterval(() => {
  timer += 1
}, 10)
