"use client";

import { useFrame } from "@react-three/fiber";
import { useMemo, useRef } from "react";
import * as THREE from "three";

function clamp(value: number, min = 0, max = 1) {
  return Math.min(Math.max(value, min), max);
}

function range(progress: number, start: number, end: number) {
  return clamp((progress - start) / (end - start));
}

function ease(value: number) {
  return value * value * (3 - 2 * value);
}

export default function CleaningCore() {
  const root = useRef<THREE.Group>(null);
  const core = useRef<THREE.Mesh>(null);
  const outerRing = useRef<THREE.Mesh>(null);
  const secondRing = useRef<THREE.Mesh>(null);
  const sweepBar = useRef<THREE.Mesh>(null);
  const rippleOne = useRef<THREE.Mesh>(null);
  const rippleTwo = useRef<THREE.Mesh>(null);
  const satellites = useRef<THREE.Group>(null);
  const particles = useRef<THREE.Points>(null);

  const particlePositions = useMemo(() => {
    const count = 550;
    const positions = new Float32Array(count * 3);

    for (let index = 0; index < count; index += 1) {
      const radius = 2.5 + Math.random() * 8;
      const angle = Math.random() * Math.PI * 2;

      positions[index * 3] = Math.cos(angle) * radius;
      positions[index * 3 + 1] = (Math.random() - 0.5) * 9;
      positions[index * 3 + 2] = Math.sin(angle) * radius;
    }

    return positions;
  }, []);

  useFrame((state, delta) => {
    if (
      !root.current ||
      !core.current ||
      !outerRing.current ||
      !secondRing.current ||
      !sweepBar.current ||
      !rippleOne.current ||
      !rippleTwo.current ||
      !satellites.current ||
      !particles.current
    ) {
      return;
    }

    const story = document.getElementById("home");

    if (!story) return;

    const rect = story.getBoundingClientRect();
    const distance = Math.max(rect.height - window.innerHeight, 1);
    const progress = clamp(-rect.top / distance);

    const homeStage = ease(range(progress, 0.12, 0.3));
    const officeStage = ease(range(progress, 0.3, 0.48));
    const fabricStage = ease(range(progress, 0.48, 0.67));
    const deepStage = ease(range(progress, 0.67, 0.84));
    const finalStage = ease(range(progress, 0.84, 1));

    const time = state.clock.elapsedTime;

    root.current.rotation.y += delta * (0.22 + progress * 0.18);
    root.current.rotation.x =
      Math.sin(time * 0.38) * 0.08 + progress * 0.1;

    const desktop = window.innerWidth > 900;

    const targetX = desktop
      ? THREE.MathUtils.lerp(4.2, 2.8, progress)
      : 0;

    const targetY = desktop
      ? THREE.MathUtils.lerp(0.2, 0.7, progress)
      : THREE.MathUtils.lerp(1.7, 1.2, progress);

    root.current.position.x = THREE.MathUtils.lerp(
      root.current.position.x,
      targetX,
      0.055,
    );

    root.current.position.y = THREE.MathUtils.lerp(
      root.current.position.y,
      targetY + Math.sin(time * 0.8) * 0.12,
      0.055,
    );

    const introScale = ease(range(progress, 0, 0.08));
    const baseScale = 0.82 + introScale * 0.18;

    root.current.scale.setScalar(
      THREE.MathUtils.lerp(
        root.current.scale.x,
        baseScale + deepStage * 0.1,
        0.06,
      ),
    );

    core.current.rotation.x += delta * 0.32;
    core.current.rotation.z -= delta * 0.23;

    const pulse =
      1 +
      Math.sin(time * 2.1) * 0.035 +
      fabricStage * Math.sin(time * 4) * 0.05;

    core.current.scale.setScalar(pulse);

    outerRing.current.rotation.x =
      Math.PI / 2 + officeStage * Math.PI * 0.5;

    outerRing.current.rotation.z += delta * (0.35 + officeStage);

    outerRing.current.scale.setScalar(
      1 + homeStage * 0.65 - deepStage * 0.2,
    );

    secondRing.current.rotation.y += delta * 0.55;
    secondRing.current.rotation.x =
      0.8 + Math.sin(time * 0.45) * 0.25;

    secondRing.current.scale.setScalar(
      0.9 + homeStage * 0.35 + fabricStage * 0.45,
    );

    sweepBar.current.visible = officeStage > 0.03 && deepStage < 0.95;
    sweepBar.current.position.x =
      THREE.MathUtils.lerp(-6, 6, officeStage);

    sweepBar.current.rotation.z =
      THREE.MathUtils.lerp(-0.35, 0.22, officeStage);

    sweepBar.current.scale.y =
      THREE.MathUtils.lerp(0.25, 1.25, officeStage);

    const rippleProgressOne = (fabricStage * 2.2) % 1;
    const rippleProgressTwo = (fabricStage * 2.2 + 0.5) % 1;

    rippleOne.current.scale.setScalar(1 + rippleProgressOne * 3.4);
    rippleTwo.current.scale.setScalar(1 + rippleProgressTwo * 3.4);

    const rippleMaterialOne =
      rippleOne.current.material as THREE.MeshBasicMaterial;
    const rippleMaterialTwo =
      rippleTwo.current.material as THREE.MeshBasicMaterial;

    rippleMaterialOne.opacity =
      fabricStage * (1 - rippleProgressOne) * 0.55;

    rippleMaterialTwo.opacity =
      fabricStage * (1 - rippleProgressTwo) * 0.42;

    satellites.current.children.forEach((child, index) => {
      const angle =
        time * (0.55 + index * 0.025) +
        (index / satellites.current!.children.length) * Math.PI * 2;

      const orbitRadius =
        THREE.MathUtils.lerp(1.6, 4.1, deepStage) -
        finalStage * 2.2;

      child.position.x = Math.cos(angle) * orbitRadius;
      child.position.z = Math.sin(angle) * orbitRadius;
      child.position.y =
        Math.sin(angle * 1.7 + index) *
        THREE.MathUtils.lerp(0.6, 2.1, deepStage);

      child.rotation.x += delta * (0.5 + index * 0.03);
      child.rotation.y += delta * (0.7 + index * 0.025);

      const satelliteScale =
        0.25 +
        deepStage * 0.55 -
        finalStage * 0.22;

      child.scale.setScalar(Math.max(satelliteScale, 0.12));
    });

    particles.current.rotation.y -= delta * 0.045;

    const particleScale =
      1.2 -
      homeStage * 0.2 -
      officeStage * 0.18 -
      deepStage * 0.35;

    particles.current.scale.setScalar(
      Math.max(particleScale, 0.42),
    );

    const particlesMaterial =
      particles.current.material as THREE.PointsMaterial;

    particlesMaterial.opacity =
      0.58 - finalStage * 0.36;
  });

  return (
    <group ref={root}>
      <points ref={particles}>
        <bufferGeometry>
          <bufferAttribute
            attach="attributes-position"
            args={[particlePositions, 3]}
          />
        </bufferGeometry>

        <pointsMaterial
          color="#53bcea"
          size={0.055}
          transparent
          opacity={0.58}
          depthWrite={false}
          blending={THREE.AdditiveBlending}
        />
      </points>

      <mesh ref={core} castShadow>
        <icosahedronGeometry args={[1.5, 5]} />

        <meshPhysicalMaterial
          color="#079ddd"
          roughness={0.12}
          metalness={0.08}
          transmission={0.3}
          thickness={1.2}
          transparent
          opacity={0.94}
          clearcoat={1}
          clearcoatRoughness={0.08}
          emissive="#006da8"
          emissiveIntensity={0.16}
        />
      </mesh>

      <mesh ref={outerRing}>
        <torusGeometry args={[2.25, 0.095, 20, 120]} />

        <meshPhysicalMaterial
          color="#ffffff"
          roughness={0.12}
          metalness={0.2}
          transmission={0.5}
          transparent
          opacity={0.85}
          clearcoat={1}
        />
      </mesh>

      <mesh ref={secondRing}>
        <torusGeometry args={[2.85, 0.055, 18, 120]} />

        <meshBasicMaterial
          color="#58c6f2"
          transparent
          opacity={0.65}
        />
      </mesh>

      <mesh ref={sweepBar} visible={false}>
        <capsuleGeometry args={[0.16, 7, 10, 20]} />

        <meshPhysicalMaterial
          color="#ffffff"
          roughness={0.08}
          metalness={0.15}
          transmission={0.45}
          transparent
          opacity={0.88}
          emissive="#1cabdf"
          emissiveIntensity={0.35}
        />
      </mesh>

      <mesh ref={rippleOne} rotation={[Math.PI / 2, 0, 0]}>
        <torusGeometry args={[1.5, 0.035, 12, 96]} />

        <meshBasicMaterial
          color="#18aee5"
          transparent
          opacity={0}
          depthWrite={false}
        />
      </mesh>

      <mesh ref={rippleTwo} rotation={[Math.PI / 2, 0, 0]}>
        <torusGeometry args={[1.5, 0.025, 12, 96]} />

        <meshBasicMaterial
          color="#ffffff"
          transparent
          opacity={0}
          depthWrite={false}
        />
      </mesh>

      <group ref={satellites}>
        {Array.from({ length: 12 }, (_, index) => (
          <mesh key={index}>
            {index % 3 === 0 ? (
              <octahedronGeometry args={[0.55, 1]} />
            ) : (
              <sphereGeometry args={[0.4, 20, 20]} />
            )}

            <meshPhysicalMaterial
              color={index % 2 === 0 ? "#ffffff" : "#25afe4"}
              roughness={0.15}
              metalness={0.1}
              transmission={index % 2 === 0 ? 0.45 : 0.12}
              transparent
              opacity={0.9}
              clearcoat={1}
            />
          </mesh>
        ))}
      </group>

      <pointLight
        color="#38b9eb"
        intensity={18}
        distance={14}
        decay={2}
      />

      <pointLight
        position={[0, 3, 3]}
        color="#ffffff"
        intensity={12}
        distance={10}
      />
    </group>
  );
}
