(function () {
  'use strict';

  const initialized = new WeakSet();

  const defaults = {
    modelUrl: '',
    autoRotateSpeed: 0.002,
    cursorStrength: 0.45,
    floatingStrength: 0.06,
    modelScale: 2.6,
    cameraZ: 5
  };

  function toNumber(value, fallback) {
    const number = Number(value);
    return Number.isFinite(number) ? number : fallback;
  }

  function getSettings(element) {
    let parsed = {};

    try {
      parsed = JSON.parse(element.getAttribute('data-hashtalk-3d') || '{}');
    } catch (error) {
      parsed = {};
    }

    return {
      modelUrl: parsed.modelUrl || defaults.modelUrl,
      autoRotateSpeed: toNumber(parsed.autoRotateSpeed, defaults.autoRotateSpeed),
      cursorStrength: toNumber(parsed.cursorStrength, defaults.cursorStrength),
      floatingStrength: toNumber(parsed.floatingStrength, defaults.floatingStrength),
      modelScale: toNumber(parsed.modelScale, defaults.modelScale),
      cameraZ: toNumber(parsed.cameraZ, defaults.cameraZ)
    };
  }

  function init3D(element) {
    if (!element || initialized.has(element)) {
      return;
    }

    if (!window.THREE || !THREE.GLTFLoader) {
      console.warn('[Hashtalk 3D] Three.js or GLTFLoader is not loaded.');
      return;
    }

    initialized.add(element);

    const settings = getSettings(element);

    if (!settings.modelUrl) {
      console.warn('[Hashtalk 3D] Model URL is empty.');
      return;
    }

    const scene = new THREE.Scene();

    const camera = new THREE.PerspectiveCamera(
      35,
      element.clientWidth / Math.max(element.clientHeight, 1),
      0.1,
      100
    );
    camera.position.set(0, 0, settings.cameraZ);

    const renderer = new THREE.WebGLRenderer({
      alpha: true,
      antialias: true
    });

    renderer.setSize(element.clientWidth, element.clientHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
    renderer.setClearColor(0x000000, 0);

    if ('outputEncoding' in renderer && THREE.sRGBEncoding) {
      renderer.outputEncoding = THREE.sRGBEncoding;
    }

    element.innerHTML = '';
    element.appendChild(renderer.domElement);

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

    const keyLight = new THREE.DirectionalLight(0xffffff, 1.45);
    keyLight.position.set(3, 4, 5);
    scene.add(keyLight);

    const fillLight = new THREE.DirectionalLight(0xff9a3d, 0.6);
    fillLight.position.set(-4, -2, 3);
    scene.add(fillLight);

    const group = new THREE.Group();
    scene.add(group);

    const targetRotation = {
      x: 0,
      y: 0,
      z: 0.45
    };

    const loader = new THREE.GLTFLoader();

    loader.load(
      settings.modelUrl,
      function (gltf) {
        const model = gltf.scene;

        model.traverse(function (child) {
          if (child.isMesh) {
            child.castShadow = false;
            child.receiveShadow = false;

            if (child.material) {
              child.material.needsUpdate = true;
            }
          }
        });

        const box = new THREE.Box3().setFromObject(model);
        const center = box.getCenter(new THREE.Vector3());
        const size = box.getSize(new THREE.Vector3());
        const maxAxis = Math.max(size.x, size.y, size.z) || 1;
        const scale = settings.modelScale / maxAxis;

        model.scale.setScalar(scale);
        model.position.set(
          -center.x * scale,
          -center.y * scale,
          -center.z * scale
        );

        group.add(model);
        element.classList.add('hashtalk-3d-element--loaded');
      },
      undefined,
      function (error) {
        console.error('[Hashtalk 3D] GLTF loading error:', error);
        element.classList.add('hashtalk-3d-element--error');
      }
    );

    function updateCursor(event) {
      const rect = element.getBoundingClientRect();
      const x = ((event.clientX - rect.left) / Math.max(rect.width, 1)) * 2 - 1;
      const y = -(((event.clientY - rect.top) / Math.max(rect.height, 1)) * 2 - 1);

      targetRotation.y = x * -settings.cursorStrength;
      targetRotation.x = y * -settings.cursorStrength * 0.55;
      targetRotation.z = x * -settings.cursorStrength * 0.16;
    }

    function resetCursor() {
      targetRotation.x = 0;
      targetRotation.y = 0;
      targetRotation.z = 0.45;
    }

    element.addEventListener('mousemove', updateCursor);
    element.addEventListener('mouseleave', resetCursor);

    function resize() {
      const width = element.clientWidth || 1;
      const height = element.clientHeight || 1;

      camera.aspect = width / height;
      camera.updateProjectionMatrix();
      renderer.setSize(width, height);
      renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
    }

    const resizeObserver = window.ResizeObserver ? new ResizeObserver(resize) : null;

    if (resizeObserver) {
      resizeObserver.observe(element);
    } else {
      window.addEventListener('resize', resize);
    }

    let frameId = null;

    function destroy() {
      if (frameId) {
        cancelAnimationFrame(frameId);
      }

      if (resizeObserver) {
        resizeObserver.disconnect();
      } else {
        window.removeEventListener('resize', resize);
      }

      element.removeEventListener('mousemove', updateCursor);
      element.removeEventListener('mouseleave', resetCursor);

      renderer.dispose();
    }

    function animate() {
      if (!document.body.contains(element)) {
        destroy();
        return;
      }

      frameId = requestAnimationFrame(animate);

      const time = performance.now() * 0.001;

      group.rotation.y += settings.autoRotateSpeed;
      group.rotation.x += (targetRotation.x - group.rotation.x) * 0.055;
      group.rotation.z += (targetRotation.z - group.rotation.z) * 0.055;

      group.position.y = Math.sin(time * 1.35) * settings.floatingStrength;

      const pulse = 1 + Math.sin(time * 1.8) * settings.floatingStrength * 0.35;
      group.scale.set(pulse, pulse, pulse);

      renderer.render(scene, camera);
    }

    resize();
    animate();
  }

  function initAll(scope) {
    const root = scope && scope.querySelectorAll ? scope : document;
    root.querySelectorAll('.hashtalk-3d-element').forEach(init3D);
  }

  function addElementorHook() {
    if (!window.elementorFrontend || !window.elementorFrontend.hooks) {
      return;
    }

    window.elementorFrontend.hooks.addAction(
      'frontend/element_ready/3d_element.default',
      function ($scope) {
        const scopeElement = $scope && $scope[0] ? $scope[0] : $scope;
        initAll(scopeElement);
      }
    );
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', function () {
      initAll(document);
    });
  } else {
    initAll(document);
  }

  if (window.jQuery) {
    window.jQuery(window).on('elementor/frontend/init', addElementorHook);
  }

  addElementorHook();
})();
