import { Html } from "@react-three/drei";
import { useFrame } from "@react-three/fiber";
import { useNavigate } from "@tanstack/react-router";
import { useRef, useState, type ReactNode } from "react";
import * as THREE from "three";
import { LIBRARIES, type LibrarySlug } from "@/lib/libraries";
import { LIBRARY_PLACEMENTS, STORE_POSITION } from "@/lib/world-layout";

const stone = "#6a5b4c";
const plinth = "#3f3a34";

function Plinth({
  children,
  label,
  onOpen,
}: {
  children: ReactNode;
  label: string;
  onOpen: () => void;
}) {
  const [hovered, setHovered] = useState(false);
  return (
    <group
      onClick={(e) => {
        e.stopPropagation();
        onOpen();
      }}
      onPointerOver={(e) => {
        e.stopPropagation();
        setHovered(true);
        document.body.style.cursor = "pointer";
      }}
      onPointerOut={() => {
        setHovered(false);
        document.body.style.cursor = "auto";
      }}
    >
      <mesh position={[0, 0.28, 0]} castShadow>
        <cylinderGeometry args={[0.72, 0.82, 0.56, 8]} />
        <meshStandardMaterial color={plinth} roughness={0.9} />
      </mesh>
      <group position={[0, hovered ? 1.22 : 1.12, 0]}>{children}</group>
      {hovered ? (
        <Html center position={[0, 2.4, 0]} sprite occlude={false}>
          <div className="lib-tag">{label}</div>
        </Html>
      ) : null}
    </group>
  );
}

function Zoetrope() {
  const inner = useRef<THREE.Mesh>(null);
  useFrame((_, dt) => {
    if (inner.current) inner.current.rotation.y += dt * 1.4;
  });
  return (
    <>
      <mesh>
        <cylinderGeometry args={[0.55, 0.55, 0.95, 16, 1, true]} />
        <meshStandardMaterial color="#cfc6b8" roughness={0.5} side={THREE.DoubleSide} />
      </mesh>
      <mesh ref={inner}>
        <cylinderGeometry args={[0.38, 0.38, 0.7, 12]} />
        <meshStandardMaterial color="#8a5a3a" roughness={0.4} />
      </mesh>
    </>
  );
}

function OrbitCubes() {
  const g = useRef<THREE.Group>(null);
  useFrame((_, dt) => {
    if (g.current) g.current.rotation.y += dt * 0.8;
  });
  return (
    <group ref={g}>
      <mesh>
        <cylinderGeometry args={[0.05, 0.05, 1.1, 6]} />
        <meshStandardMaterial color="#d9d1c5" />
      </mesh>
      {([0, 2.1, 4.2] as const).map((a, i) => (
        <mesh key={i} position={[Math.cos(a) * 0.45, Math.sin(a * 2) * 0.15, Math.sin(a) * 0.45]}>
          <boxGeometry args={[0.22, 0.22, 0.22]} />
          <meshStandardMaterial color={i === 1 ? "#c4a882" : "#ece6dc"} roughness={0.35} />
        </mesh>
      ))}
    </group>
  );
}

function Storyboards() {
  return (
    <>
      <mesh rotation={[0.1, -0.2, 0.04]} position={[0, 0.05, 0]}>
        <boxGeometry args={[0.85, 0.04, 0.55]} />
        <meshStandardMaterial color="#e6ddd0" />
      </mesh>
      <mesh rotation={[-0.08, 0.25, -0.05]} position={[0.05, 0.18, 0.02]}>
        <boxGeometry args={[0.8, 0.04, 0.5]} />
        <meshStandardMaterial color="#c8b8a2" />
      </mesh>
      <mesh rotation={[0.04, 0.05, 0.1]} position={[-0.04, 0.32, 0]}>
        <boxGeometry args={[0.78, 0.04, 0.48]} />
        <meshStandardMaterial color="#9a7a58" />
      </mesh>
    </>
  );
}

function Bust() {
  return (
    <>
      <mesh position={[0, 0.35, 0]}>
        <sphereGeometry args={[0.28, 16, 12]} />
        <meshStandardMaterial color="#d7cbb8" roughness={0.55} />
      </mesh>
      <mesh position={[0, 0.02, 0]}>
        <boxGeometry args={[0.62, 0.28, 0.28]} />
        <meshStandardMaterial color="#cfc3b0" roughness={0.6} />
      </mesh>
    </>
  );
}

function MiniKeep() {
  return (
    <>
      <mesh position={[0, -0.1, 0]}>
        <boxGeometry args={[0.8, 0.18, 0.8]} />
        <meshStandardMaterial color="#a18462" />
      </mesh>
      <mesh position={[0, 0.12, 0]}>
        <boxGeometry args={[0.55, 0.28, 0.55]} />
        <meshStandardMaterial color="#8c6d4e" />
      </mesh>
      <mesh position={[0.08, 0.4, 0.05]}>
        <boxGeometry args={[0.28, 0.4, 0.28]} />
        <meshStandardMaterial color="#6f5a48" />
      </mesh>
    </>
  );
}

function Crate() {
  return (
    <>
      <mesh>
        <boxGeometry args={[0.7, 0.5, 0.55]} />
        <meshStandardMaterial color="#8a6a45" roughness={0.85} />
      </mesh>
      <mesh position={[0.38, 0.15, 0]} rotation={[0, 0, 0.4]}>
        <cylinderGeometry args={[0.05, 0.05, 0.7, 8]} />
        <meshStandardMaterial color="#cfc6b8" metalness={0.4} roughness={0.35} />
      </mesh>
    </>
  );
}

function Easel() {
  return (
    <>
      <mesh position={[-0.18, 0.1, 0]} rotation={[0, 0, 0.18]}>
        <boxGeometry args={[0.06, 1.1, 0.06]} />
        <meshStandardMaterial color="#5c4a38" />
      </mesh>
      <mesh position={[0.18, 0.1, 0]} rotation={[0, 0, -0.18]}>
        <boxGeometry args={[0.06, 1.1, 0.06]} />
        <meshStandardMaterial color="#5c4a38" />
      </mesh>
      <mesh position={[0, 0.28, 0.08]} rotation={[-0.12, 0, 0]}>
        <boxGeometry args={[0.7, 0.55, 0.04]} />
        <meshStandardMaterial color="#ece6dc" />
      </mesh>
    </>
  );
}

function Figure() {
  return (
    <>
      <mesh position={[0, 0.42, 0]}>
        <sphereGeometry args={[0.14, 12, 10]} />
        <meshStandardMaterial color="#d7cbb8" />
      </mesh>
      <mesh position={[0, 0.08, 0]}>
        <cylinderGeometry args={[0.13, 0.16, 0.55, 8]} />
        <meshStandardMaterial color="#cfc3b0" />
      </mesh>
    </>
  );
}

const ICONS: Record<LibrarySlug, ReactNode> = {
  "2d-animation": <Zoetrope />,
  "3d-animation": <OrbitCubes />,
  concepting: <Storyboards />,
  "character-design": <Bust />,
  "level-design": <MiniKeep />,
  diy: <Crate />,
  "traditional-art": <Easel />,
  "life-drawing": <Figure />,
};

export function LibraryCairns() {
  const navigate = useNavigate();
  return (
    <>
      {LIBRARY_PLACEMENTS.map((p) => {
        const lib = LIBRARIES.find((l) => l.slug === p.slug);
        if (!lib) return null;
        return (
          <group key={p.slug} position={p.position}>
            <Plinth
              label={lib.name}
              onOpen={() => navigate({ to: "/library/$slug", params: { slug: p.slug } })}
            >
              {ICONS[p.slug]}
            </Plinth>
          </group>
        );
      })}
    </>
  );
}

export function StoreTable() {
  const navigate = useNavigate();
  const [hovered, setHovered] = useState(false);
  return (
    <group
      position={STORE_POSITION}
      onClick={(e) => {
        e.stopPropagation();
        void navigate({ to: "/store" });
      }}
      onPointerOver={(e) => {
        e.stopPropagation();
        setHovered(true);
        document.body.style.cursor = "pointer";
      }}
      onPointerOut={() => {
        setHovered(false);
        document.body.style.cursor = "auto";
      }}
    >
      <mesh position={[0, 0.45, 0]} castShadow>
        <boxGeometry args={[2.4, 0.12, 1.2]} />
        <meshStandardMaterial color={hovered ? "#8a7a68" : stone} roughness={0.88} />
      </mesh>
      <mesh position={[-0.9, 0.2, 0.4]}>
        <boxGeometry args={[0.12, 0.4, 0.12]} />
        <meshStandardMaterial color={plinth} />
      </mesh>
      <mesh position={[0.9, 0.2, 0.4]}>
        <boxGeometry args={[0.12, 0.4, 0.12]} />
        <meshStandardMaterial color={plinth} />
      </mesh>
      <mesh position={[-0.9, 0.2, -0.4]}>
        <boxGeometry args={[0.12, 0.4, 0.12]} />
        <meshStandardMaterial color={plinth} />
      </mesh>
      <mesh position={[0.9, 0.2, -0.4]}>
        <boxGeometry args={[0.12, 0.4, 0.12]} />
        <meshStandardMaterial color={plinth} />
      </mesh>
      {([-0.65, 0, 0.65] as const).map((x, i) => (
        <mesh key={i} position={[x, 0.72, 0]} rotation={[-0.18, 0.1 * (i - 1), 0]}>
          <boxGeometry args={[0.5, 0.38, 0.03]} />
          <meshStandardMaterial color={i === 1 ? "#d9cbb8" : "#c4b09a"} />
        </mesh>
      ))}
      {hovered ? (
        <Html center position={[0, 1.55, 0]} sprite occlude={false}>
          <div className="lib-tag">Store</div>
        </Html>
      ) : null}
    </group>
  );
}
