import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import {
  CSS2DRenderer,
  CSS2DObject,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";

//scene
const scene = new THREE.Scene();

//camera
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  1,
  1000
);
camera.position.set(0, 0, 14);
camera.lookAt(scene.position);

//renderer
const renderer = new THREE.WebGLRenderer({
  antialias: true,
});
renderer.setClearColor(0x000000);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// CSS2D Renderer for HTML labels
const labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = "absolute";
labelRenderer.domElement.style.top = "0";
document.body.appendChild(labelRenderer.domElement);

//orbti controls
const controls = new OrbitControls(camera, renderer.domElement);
// controls.autoRotate = true;
// controls.autoRotateSpeed = 2.0;

//create globe

const geom = new THREE.SphereBufferGeometry(5, 180, 90);

//load map texture
const loader = new THREE.TextureLoader();
loader.setCrossOrigin("");
const texture = loader.load("/earthspec1k.jpg");
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(1, 1);

//particle texture
const disk = loader.load("/circle.png");

const points = new THREE.Points(
  geom,
  new THREE.ShaderMaterial({
    vertexColors: THREE.VertexColors,
    uniforms: {
      visibility: {
        value: texture,
      },
      shift: {
        value: 0,
      },
      shape: {
        value: disk,
      },
      size: {
        value: 0.2,
      },
      scale: {
        value: window.innerHeight / 2,
      },
    },
    vertexShader: `
      uniform float scale;
      uniform float size;
      varying vec2 vUv;
      varying vec3 vColor;
      
      void main() {
        vUv = uv;
        vColor = color;
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        gl_PointSize = size * ( scale / length( mvPosition.xyz )) * (0.3 + sin(uv.y * 3.1415926) * 0.6 );
        gl_Position = projectionMatrix * mvPosition;
      }
    `,
    fragmentShader: `
      uniform sampler2D visibility;
      uniform float shift;
      uniform sampler2D shape;
      varying vec2 vUv;
      varying vec3 vColor;
      
      void main() {
        vec2 uv = vUv;
        uv.x += shift;
        vec4 v = texture2D(visibility, uv);
        if (length(v.rgb) > 1.0) discard;
        gl_FragColor = vec4(vColor, 1.0);
        vec4 shapeData = texture2D(shape, gl_PointCoord);
        if (shapeData.a < 0.0625) discard;
        gl_FragColor = gl_FragColor * shapeData;
      }
    `,
    transparent: false,
  })
);

scene.add(points);

var blackGlobe = new THREE.Mesh(
  geom,
  new THREE.MeshBasicMaterial({
    color: 0xffffff,
    transparent: true,
    opacity: 0,
  })
);
blackGlobe.scale.setScalar(0.99);
points.add(blackGlobe);

// Helper function to create pinpoints with labels
function createPinpoint(latitude, longitude, labelText) {
  const radius = 5; // Sphere radius
  const phi = (90 - latitude) * (Math.PI / 180);
  const theta = (longitude + 180) * (Math.PI / 180);

  const x = -(radius * Math.sin(phi) * Math.cos(theta));
  const y = radius * Math.cos(phi);
  const z = radius * Math.sin(phi) * Math.sin(theta);

  const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
  const pinpoint = new THREE.Mesh(
    new THREE.SphereGeometry(0.1, 16, 16),
    material
  );
  pinpoint.position.set(x, y, z);

  // Create label
  const labelDiv = document.createElement("div");
  labelDiv.className = "label";
  labelDiv.style.color = "#fff";
  labelDiv.style.backgroundColor = "rgba(0,0,0,0.8)";
  labelDiv.style.padding = "4px";
  labelDiv.style.borderRadius = "4px";
  labelDiv.innerText = labelText;

  const label = new CSS2DObject(labelDiv);
  label.position.set(0, 0, 0);
  pinpoint.add(label);

  scene.add(pinpoint);
  return pinpoint; // return pinpoint for raycasting
}

// Create pinpoints and labels
const pinpoints = [];
pinpoints.push(createPinpoint(0, 0, "Location A"));
pinpoints.push(createPinpoint(45, 45, "Location B"));
pinpoints.push(createPinpoint(-30, -60, "Location C"));
pinpoints.push(createPinpoint(-20, 60, "Location D"));

// Raycaster and mouse vector
const raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
let isHovering = false;

function onMouseMove(event) {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  // Update raycaster
  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObjects([blackGlobe]);
  console.log(intersects);
  // Check if the mouse is hovering over the mesh
  isHovering = intersects.length > 0;
  // if (isHovering) {
  //   controls.autoRotate = false;
  // } else {
  //   controls.autoRotate = true;
  // }
}

window.addEventListener("mousemove", onMouseMove, false);
window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

var clock = new THREE.Clock();
var time = 0;

render();

function render() {
  requestAnimationFrame(render);
  time += clock.getDelta();

  controls.update();

  renderer.render(scene, camera);
}


"orbit control not work"