import {
  Camera, Color, Geometry, Mesh, Plane, Program, Renderer, Transform
} from "ogl";

const rand = (amount = 1) => amount * (Math.random() * 2 - 1);

import FishModel from "./fishModel";
import FishFrag from "./shaders/Fish.frag";
import FishVert from "./shaders/Fish.vert";
import SeeweedFrag from "./shaders/Seeweed.frag";
import SeeweedVert from "./shaders/Seeweed.vert";

export default (canvas: HTMLCanvasElement, { amount = 100, color = new Color(0xffffff) }: { amount?: number, color?: Color } = {}) => {
  const renderer = new Renderer({
    canvas,
    antialias: true,
  });

  const { gl } = renderer;

  gl.clearColor(color.r, color.g, color.b, 1);

  const scene = new Transform();

  const camParent = new Transform();
  const camera = new Camera(gl, { fov: 15 });
  camera.position.z = 15;
  camera.setParent(camParent);

  camParent.setParent(scene);

  const fishAmount = 10;
  let fishOffset = new Float32Array(fishAmount * 3);
  let fishRandom = new Float32Array(fishAmount * 3);
  for (let i = 0; i < fishAmount; i++) {
    fishOffset.set([Math.random() * 10, rand(50.0), rand(10.0)], i * 3);
    fishRandom.set([Math.random(), Math.random(), Math.random()], i * 3);
  }
  const fishMesh = new Mesh(gl, {
    geometry: new Geometry(gl, {
      ...FishModel,
      offset: { instanced: 1, size: 3, data: fishOffset },
      random: { instanced: 1, size: 3, data: fishRandom },
    }),
    program: new Program(gl, {
      uniforms: {
        uTime: { value: 0 },
        uFogColor: { value: color },
      },
      vertex: FishVert,
      fragment: FishFrag,
      cullFace: gl.NONE,
    }),
  });
  fishMesh.scale.scale(0.1);
  fishMesh.position.y = 1.5;
  fishMesh.rotation.set([Math.PI, Math.PI / 2, Math.PI / 2]);
  fishMesh.setParent(scene);

  const program = new Program(gl, {
    vertex: SeeweedVert,
    fragment: SeeweedFrag,
    cullFace: gl.NONE,
    uniforms: {
      uTime: { value: 0 },
      uFogColor: { value: color },
      uFogNear: { value: 50 },
      uFogFar: { value: 100 },
    },
  });

  let offset = new Float32Array(amount * 3);
  let random = new Float32Array(amount * 3);
  for (let i = 0; i < amount; i++) {
    offset.set([rand(3.3), rand(0.4), rand(2)], i * 3);
    random.set([Math.random() * 5, Math.random() * 2, rand()], i * 3);
  }

  const geometry = new Plane(gl, {
    width: 0.1,
    heightSegments: 8,
    attributes: {
      offset: { instanced: 1, size: 3, data: offset },
      random: { instanced: 1, size: 3, data: random },
    },
  });

  const mesh = new Mesh(gl, { geometry, program });
  mesh.position.y = 1.5;
  mesh.setParent(scene);

  return {
    update: (t: number, timeOffset: number) => {
      program.uniforms.uTime.value = t * 0.001 + timeOffset;
      fishMesh.program.uniforms.uTime.value = t * 0.001;
      renderer.render({ scene, camera });
    },
    resize: () => {
      let height = window.innerHeight;
      let width = window.innerWidth;
      renderer.setSize(width, height);
      gl.clearColor(color.r, color.g, color.b, 1);
      camera.perspective({ aspect: gl.canvas.width / gl.canvas.height });
    },
  };
};
