"use client";

import { useEffect, useRef } from "react";
import { useTheme } from "next-themes";
import Matter from "matter-js";
import { twj } from "tw-to-css";

export function World() {
  const containerRef = useRef<HTMLDivElement>(null);
  const { resolvedTheme } = useTheme();

  const getRandomXY = (width: number, height: number, radius: number) => {
    const randomX = Math.floor(Math.random() * (width - 2 * radius)) + radius;
    const randomY = Math.floor(Math.random() * (height - 2 * radius)) + radius;
    return [randomX, randomY];
  };

  useEffect(() => {
    const pillTexts: HTMLDivElement[] = [];

    let container = containerRef.current;
    if (!container) {
      return;
    }

    const width = container.offsetWidth;
    const height = container.offsetHeight;

    // TODO: ask Shubh about using variables in useEffect not working as expected
    // const bgColor = getComputedStyle(document.documentElement)
    //   .getPropertyValue("--color-background")
    //   .trim();
    // const fgColor = getComputedStyle(document.documentElement)
    //   .getPropertyValue("--color-foreground")
    //   .trim();
    const bgColor =
      resolvedTheme === "dark" ? "oklch(0.145 0 0)" : "oklch(1 0 0)";
    const fgColor =
      resolvedTheme === "dark" ? "oklch(0.985 0 0)" : "oklch(0.145 0 0)";

    const {
      Engine,
      Events,
      Render,
      Bodies,
      Composite,
      Runner,
      Mouse,
      MouseConstraint,
    } = Matter;
    const engine = Engine.create();
    engine.gravity.y = 0.3;
    engine.enableSleeping = true;

    const render = Render.create({
      element: container,
      engine,
      options: {
        width,
        height,
        wireframes: false,
        background: bgColor,
      },
    });

    // Bottom wall (ground)
    const ground = Bodies.rectangle(width / 2, height - 10, width, 20, {
      isStatic: true,
      render: { fillStyle: bgColor },
    });

    // Left wall
    const leftWall = Bodies.rectangle(-10, height / 2, 20, height + 40, {
      isStatic: true,
      render: { fillStyle: bgColor },
    });

    // Right wall
    const rightWall = Bodies.rectangle(
      width + 10,
      height / 2,
      20,
      height + 40,
      {
        isStatic: true,
        render: { fillStyle: bgColor },
      },
    );

    // Top wall
    const topWall = Bodies.rectangle(width / 2, -10, width, 20, {
      isStatic: true,
      render: { fillStyle: bgColor },
    });

    // Random ball position
    const ballRadius = 15;

    let [randomX, randomY] = getRandomXY(width, height, ballRadius);
    const ballRed = Bodies.circle(randomX, randomY, ballRadius, {
      restitution: 0.8,
      render: { fillStyle: "red" },
    });
    [randomX, randomY] = getRandomXY(width, height, ballRadius);
    const ballBlue = Bodies.circle(randomX, randomY, ballRadius, {
      restitution: 0.8,
      render: { fillStyle: "blue" },
    });
    [randomX, randomY] = getRandomXY(width, height, ballRadius);
    const ballGreen = Bodies.circle(randomX, randomY, ballRadius, {
      restitution: 0.8,
      render: { fillStyle: "green" },
    });

    // Mouse interaction
    const mouse = Mouse.create(render.canvas);
    const mouseConstraint = MouseConstraint.create(engine, {
      mouse,
      constraint: {
        stiffness: 1,
        angularStiffness: 0,
        render: { visible: false },
      },
    });

    const pills: Matter.Body[] = [];
    const pillsToRenderInfo = [
      { text: "ENGINEERING MANAGER" },
      { text: "PRINCIPAL ENGINEER" },
      { text: "NIX", chamferRadius: 20 },
      { text: "AI", chamferRadius: 20 },
    ];

    pillsToRenderInfo.forEach(function (pillInfo) {
      const fontSize = 32;

      const pillText = pillInfo.text;

      const ctx = render.canvas.getContext("2d");
      ctx.font = `${fontSize}px Mono`;
      const textWidth = ctx.measureText(pillText).width;

      const pillHeight = fontSize * 2;
      const pillWidth = textWidth + pillHeight;
      [randomX, randomY] = getRandomXY(width, height, pillWidth / 2);
      const chamferRadius = pillInfo.chamferRadius || pillHeight / 2;
      const pill = Matter.Bodies.rectangle(
        randomX,
        randomY,
        pillWidth,
        pillHeight,
        {
          chamfer: { radius: chamferRadius },
          isStatic: false,
          density: 0.001,
          friction: 0.05,
          frictionAir: 0.01,
          render: {
            fillStyle: "rgba(255, 255, 255, 0)", // transparent fill
            strokeStyle: fgColor, // black border
            lineWidth: 1,
          },
        },
      );

      pills.push(pill);
      const text: HTMLDivElement = document.createElement("div");
      Object.assign(text.style, {
        ...twj("absolute flex justify-center items-center"),
        ...{
          width: `${pillWidth}px`,
          height: `${pillHeight}px`,
          fontFamily: "Space Mono",
          fontSize: `${fontSize}px`,
          color: fgColor,
          pointerEvents: "none",
        },
      });
      text.innerText = pillText;
      pillTexts.push(text);

      render.canvas.getContext("2d").measure;
      document.body.appendChild(text);

      Events.on(engine, "afterUpdate", () => {
        text.style.left = `${pill.position.x - pillWidth / 2 + 60}px`;
        text.style.top = `${pill.position.y + pillHeight / 2 - 4}px`;
        text.style.transform = `rotate(${pill.angle}rad)`;
      });
    });

    // Add all elements to the world
    Composite.add(engine.world, [
      ground,
      leftWall,
      rightWall,
      topWall,
      ballGreen,
      ballBlue,
      ballRed,
      ...pills,
      mouseConstraint,
    ]);

    Render.run(render);
    const runner = Runner.create();
    Runner.run(runner, engine);

    return () => {
      Render.stop(render);
      Runner.stop(runner);
      Composite.clear(engine.world);
      Engine.clear(engine);
      render.canvas.remove();
      pillTexts.forEach((pillText) => {
        pillText.remove();
      });
    };
  }, [resolvedTheme]);

  return (
    <div
      ref={containerRef}
      className="w-[95vw] h-[40vh] mx-auto relative overflow-hidden"
    />
  );
}
