import { onMount, onCleanup, createEffect } from "solid-js";
import type { Component } from "solid-js";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import html2canvas from "html2canvas";

interface TabletPreviewProps {
  dashboardElement?: HTMLElement | null;
}

export const TabletPreview: Component<TabletPreviewProps> = (props) => {
  let canvasRef: HTMLCanvasElement | undefined;
  let scene: THREE.Scene;
  let camera: THREE.PerspectiveCamera;
  let renderer: THREE.WebGLRenderer;
  let tablet: THREE.Group;
  let screen: THREE.Mesh;
  let animationFrameId: number;
  let updateInterval: number;
  let controls: OrbitControls;

  const createTablet = () => {
    const group = new THREE.Group();

    const screenGeometry = new THREE.PlaneGeometry(6, 4);
    const screenMaterial = new THREE.MeshStandardMaterial({
      color: 0xeeeeee,
      roughness: 0.9,
      metalness: 0.05,
      side: THREE.DoubleSide,
    });
    const screenMesh = new THREE.Mesh(screenGeometry, screenMaterial);
    screenMesh.position.z = 0.07;
    group.add(screenMesh);

    const frameMaterial = new THREE.MeshStandardMaterial({
      color: 0x0a0a0a,
      roughness: 0.6,
      metalness: 0.3,
    });

    const topFrame = new THREE.Mesh(
      new THREE.BoxGeometry(6.2, 0.2, 0.15),
      frameMaterial,
    );
    topFrame.position.y = 2.1;
    topFrame.position.z = 0.04;
    group.add(topFrame);

    const sideFrame = new THREE.Mesh(
      new THREE.BoxGeometry(0.1, 4, 0.15),
      frameMaterial,
    );
    sideFrame.position.x = -3.05;
    sideFrame.position.z = 0.04;
    group.add(sideFrame);

    const rightSideFrame = sideFrame.clone();
    rightSideFrame.position.x = 3.05;
    group.add(rightSideFrame);

    const bottomFrame = new THREE.Mesh(
      new THREE.BoxGeometry(6.2, 0.2, 0.15),
      frameMaterial,
    );
    bottomFrame.position.y = -2.1;
    bottomFrame.position.z = 0.04;
    group.add(bottomFrame);

    const backPlate = new THREE.Mesh(
      new THREE.BoxGeometry(6.5, 4.5, 0.12),
      frameMaterial,
    );
    backPlate.position.z = -0.18;
    group.add(backPlate);

    return { group, screen: screenMesh };
  };

  const updateScreenTexture = async () => {
    const gridContainer = document.querySelector(
      "[data-grid-container]",
    ) as HTMLElement;
    if (!gridContainer || !screen) return;

    try {
      const rect = gridContainer.getBoundingClientRect();

      const canvas = await html2canvas(gridContainer, {
        scale: 1.5,
        backgroundColor: "#ffffff",
        logging: false,
        useCORS: true,
        width: rect.width,
        height: rect.height,
        windowWidth: rect.width,
        windowHeight: rect.height,
      });

      const texture = new THREE.CanvasTexture(canvas);
      texture.needsUpdate = true;

      texture.wrapS = THREE.ClampToEdgeWrapping;
      texture.wrapT = THREE.ClampToEdgeWrapping;
      texture.minFilter = THREE.LinearFilter;
      texture.magFilter = THREE.LinearFilter;

      const canvasAspect = canvas.width / canvas.height;
      const screenAspect = 6 / 4;

      if (canvasAspect > screenAspect) {
        const scale = screenAspect / canvasAspect;
        texture.repeat.set(1, 1 / scale);
        texture.offset.set(0, (1 - texture.repeat.y) / 2);
      } else {
        const scale = canvasAspect / screenAspect;
        texture.repeat.set(1 / scale, 1);
        texture.offset.set((1 - texture.repeat.x) / 2, 0);
      }

      const material = screen.material as THREE.MeshStandardMaterial;
      material.map = texture;
      material.needsUpdate = true;
    } catch (error) {
      console.error("Failed to capture dashboard:", error);
    }
  };

  onMount(() => {
    if (!canvasRef) return;

    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(
      50,
      canvasRef.clientWidth / canvasRef.clientHeight,
      0.1,
      1000,
    );
    renderer = new THREE.WebGLRenderer({
      canvas: canvasRef,
      alpha: true,
      antialias: true,
    });

    renderer.setSize(canvasRef.clientWidth, canvasRef.clientHeight);
    renderer.setClearColor(0x000000, 0);

    const tabletResult = createTablet();
    tablet = tabletResult.group;
    screen = tabletResult.screen;
    scene.add(tablet);

    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
    scene.add(ambientLight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(3, 3, 5);
    scene.add(directionalLight);

    const rimLight = new THREE.DirectionalLight(0xff6b6b, 0.2);
    rimLight.position.set(-3, 0, -3);
    scene.add(rimLight);

    camera.position.set(0, 2, 16);
    camera.lookAt(0, 0, 0);

    tablet.rotation.x = -0.15;
    tablet.rotation.y = 0.08;

    controls = new OrbitControls(camera, canvasRef);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;
    controls.enableZoom = true;
    controls.enablePan = false;
    controls.minDistance = 8;
    controls.maxDistance = 25;
    controls.autoRotate = false;
    controls.rotateSpeed = 0.5;

    const animate = () => {
      animationFrameId = requestAnimationFrame(animate);

      controls.update();

      tablet.position.y = Math.sin(Date.now() * 0.0005) * 0.05;

      renderer.render(scene, camera);
    };

    animate();

    updateScreenTexture();
    updateInterval = window.setInterval(() => {
      updateScreenTexture();
    }, 2000);

    const handleResize = () => {
      if (!canvasRef) return;
      camera.aspect = canvasRef.clientWidth / canvasRef.clientHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(canvasRef.clientWidth, canvasRef.clientHeight);
    };

    window.addEventListener("resize", handleResize);

    onCleanup(() => {
      window.removeEventListener("resize", handleResize);
      cancelAnimationFrame(animationFrameId);
      clearInterval(updateInterval);
      renderer.dispose();
    });
  });

  return (
    <canvas
      ref={canvasRef}
      style={{
        width: "100%",
        height: "100%",
      }}
    />
  );
};
