'use client';

import './page.css';

import { Environment, OrbitControls, useProgress } from "@react-three/drei";
import { Canvas, useLoader } from '@react-three/fiber';
import { Bloom, BrightnessContrast, DepthOfField, EffectComposer, HueSaturation, LUT, Noise, SMAA, SSAO, Vignette } from '@react-three/postprocessing';
import { useLayoutEffect, useState } from "react";
import { folder, useControls, Leva } from 'leva';
import SealCube from './scene-components/sealcube';
import Terrain from './scene-components/terrain';
import { LUTCubeLoader } from 'three/examples/jsm/Addons.js';
import { AmbientSound } from './scene-components/ambient-sound';

function Loader() {
  const { progress, active } = useProgress();
  const [visible, setVisible] = useState(true);

  useLayoutEffect(() => {
    if (!active && progress === 100) {
      const timeout = setTimeout(() => setVisible(false), 500);
      return () => clearTimeout(timeout);
    }
  }, [progress, active]);

  return (
    <div className={`loader ${!visible ? 'loader hidden' : ''}`}>
      <picture>
        <img src='niko/img/niko.jpg' className='niko-spin' />
      </picture>
    </div>
  );
}

function Scene() {
  const {
    terrainDryColor,
    terrainLushColor,
    chunks,
    chunkSize,
    resolution,
    hillScale,
    hillHeight,
    detailScale,
    detailHeight,
    grassDryColor,
    grassLushColor,
    grassCount,
    grassSize,
    grassLOD,
    grassBlades,
    grassSegments,
    grassLODStart,
    grassLODExponent
  } = useControls('Environment', {
    Terrain: folder({
      terrainDryColor: '#232a0c',
      terrainLushColor: '#142a14',
      chunks: { value: 16, min: 4, max: 24, step: 2 },
      chunkSize: { value: 10.0, min: 5.0, max: 40.0, step: 1.0 },
      resolution: { value: 8.0, min: 4.0, max: 30.0, step: 1.0 },
      hillScale: { value: 0.15, min: 0.01, max: 0.5, step: 0.01 },
      hillHeight: { value: 4.0, min: 0.0, max: 20.0, step: 0.5 },
      detailScale: { value: 1.0, min: 0.1, max: 5.0, step: 0.1 },
      detailHeight: { value: 0.3, min: 0.0, max: 2.0, step: 0.05 },
    }),
    Grass: folder({
      grassDryColor: '#495a17',
      grassLushColor: '#255825',
      grassCount: { value: 8000, min: 1000, max: 30000, step: 500 },
      grassSize: { value: 0.65, min: 0.1, max: 2.0, step: 0.05 },
      grassLOD: { value: 60, min: 10, max: 200, step: 5 },
      grassBlades: { value: 3, min: 1, max: 4, step: 1 },
      grassSegments: { value: 3, min: 1, max: 5, step: 1 },
      grassLODStart: { value: 0.15, min: 0.0, max: 0.9, step: 0.05 },
      grassLODExponent: { value: 1.8, min: 0.5, max: 3.0, step: 0.1 },
    })
  });

  return (<>
    <Environment
      files={'niko/hdr/sky.hdr'}
      environmentIntensity={0.85}
      background
    />

    <fogExp2 attach='fog' args={[0x9a9a9a, 0.0125]} />

    <ambientLight intensity={0.5} />
    <directionalLight
      position={[15, 25, 15]}
      intensity={1}
    />

    <Terrain
      chunks={chunks}
      chunkSize={chunkSize}
      resolution={resolution}
      scale={1}
      hillScale={hillScale}
      hillHeight={hillHeight}
      detailScale={detailScale}
      detailHeight={detailHeight}
      grassCount={grassCount}
      grassSize={grassSize}
      grassLOD={grassLOD}
      terrainDryColor={terrainDryColor}
      terrainLushColor={terrainLushColor}
      grassDryColor={grassDryColor}
      grassLushColor={grassLushColor}
      grassBlades={grassBlades}
      grassSegments={grassSegments}
      grassLODStart={grassLODStart}
      grassLODExponent={grassLODExponent}
    />

    <SealCube />
  </>)
}

function LutEffect() {
  const lutTexture = useLoader(LUTCubeLoader, 'niko/lut/Landscape6.cube');
  return <LUT lut={lutTexture.texture3D} />;
}

function PostProcessing() {
  return (<EffectComposer>
    <DepthOfField target={[0, 3, 0]} focalLength={10} bokehScale={5} />
    <Vignette />
    <Noise opacity={0.05} />
    <Bloom
      intensity={0.8}
      luminanceThreshold={0.4}
      luminanceSmoothing={0.5}
    />
    <SMAA />
    <HueSaturation saturation={0.3} />
    <BrightnessContrast brightness={0.05} contrast={-0.1} />
    <LutEffect />
  </EffectComposer>)
}

export default function Seal() {
  const isProduction = process.env.NODE_ENV === 'production';

  return (
    <>
      <Leva hidden={isProduction} />

      <Loader />
      <Canvas
        shadows
        camera={{ position: [0, 5, 15], fov: 50, far: 100 }}
        gl={{ antialias: false, powerPreference: "high-performance" }}
        className='canvas'
      >
        <AmbientSound url="niko/snd/wind.mp3" volume={0.4}/>
        <AmbientSound url="niko/snd/birds.mp3" volume={0.1}/>

        <Scene />
        <PostProcessing />

        <OrbitControls
          target={[0, 3, 0]}
          enablePan={false}
          makeDefault
          minDistance={2}
          maxDistance={6}
        />
      </Canvas>
    </>
  );
}