/* ============================================================
   OPZEKER IT — MODERN JS
   - Three.js animated WebGL hero (particle network / torus knot)
   - Typed text rotator
   - Scroll reveal (IntersectionObserver)
   - Spotlight hover on service cards
   - Magnetic nav, sticky header, scrollspy, smooth scroll
   - Counter up, skill bars animation
   ============================================================ */
(function () {
    'use strict';

    /* ---------- Helpers ---------- */
    const $  = (s, r = document) => r.querySelector(s);
    const $$ = (s, r = document) => Array.from(r.querySelectorAll(s));
    const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    /* ============================================================
       1. THREE.JS WEBGL HERO BACKGROUND
       Dynamic particle network + glowing torus knot
       ============================================================ */
    function initWebGLHero() {
        const container = document.getElementById('mx-webgl');
        if (!container || typeof THREE === 'undefined') return;

        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(
            55,
            container.clientWidth / container.clientHeight,
            0.1,
            1000
        );
        camera.position.z = 18;

        const renderer = new THREE.WebGLRenderer({
            antialias: true,
            alpha: true,
            powerPreference: 'high-performance'
        });
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        renderer.setSize(container.clientWidth, container.clientHeight);
        renderer.setClearColor(0x000000, 0);
        container.appendChild(renderer.domElement);

        /* ----- Glowing torus knot (center hero object) ----- */
        const knotGeo = new THREE.TorusKnotGeometry(3.2, 0.55, 220, 28, 2, 3);
        const knotMat = new THREE.MeshBasicMaterial({
            color: 0x9600f4,
            wireframe: true,
            transparent: true,
            opacity: 0.28
        });
        const knot = new THREE.Mesh(knotGeo, knotMat);
        scene.add(knot);

        // Second ghostly knot for parallax
        const knot2Mat = new THREE.MeshBasicMaterial({
            color: 0x00f2ff,
            wireframe: true,
            transparent: true,
            opacity: 0.18
        });
        const knot2 = new THREE.Mesh(knotGeo, knot2Mat);
        knot2.scale.setScalar(1.15);
        scene.add(knot2);

        /* ----- Particle starfield ----- */
        const particleCount = prefersReducedMotion ? 400 : 1400;
        const positions = new Float32Array(particleCount * 3);
        const colors    = new Float32Array(particleCount * 3);
        const colorA = new THREE.Color(0x00f2ff);
        const colorB = new THREE.Color(0xd42bff);

        for (let i = 0; i < particleCount; i++) {
            const i3 = i * 3;
            // distribute in a large sphere shell
            const r = 10 + Math.random() * 30;
            const theta = Math.random() * Math.PI * 2;
            const phi   = Math.acos(2 * Math.random() - 1);
            positions[i3]     = r * Math.sin(phi) * Math.cos(theta);
            positions[i3 + 1] = r * Math.sin(phi) * Math.sin(theta);
            positions[i3 + 2] = r * Math.cos(phi);

            const c = colorA.clone().lerp(colorB, Math.random());
            colors[i3]     = c.r;
            colors[i3 + 1] = c.g;
            colors[i3 + 2] = c.b;
        }

        const pGeo = new THREE.BufferGeometry();
        pGeo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
        pGeo.setAttribute('color',    new THREE.BufferAttribute(colors,    3));

        const pMat = new THREE.PointsMaterial({
            size: 0.08,
            vertexColors: true,
            transparent: true,
            opacity: 0.9,
            sizeAttenuation: true,
            blending: THREE.AdditiveBlending,
            depthWrite: false
        });
        const points = new THREE.Points(pGeo, pMat);
        scene.add(points);

        /* ----- Interaction: mouse parallax ----- */
        const target = { x: 0, y: 0 };
        const current = { x: 0, y: 0 };

        container.parentElement.addEventListener('mousemove', (e) => {
            const rect = container.getBoundingClientRect();
            target.x = ((e.clientX - rect.left) / rect.width  - 0.5) * 2;
            target.y = ((e.clientY - rect.top)  / rect.height - 0.5) * 2;
        });

        /* ----- Resize ----- */
        function onResize() {
            const w = container.clientWidth;
            const h = container.clientHeight;
            camera.aspect = w / h;
            camera.updateProjectionMatrix();
            renderer.setSize(w, h);
        }
        window.addEventListener('resize', onResize);

        /* ----- Animate ----- */
        let rafId;
        const clock = new THREE.Clock();
        function animate() {
            const t = clock.getElapsedTime();

            // Smooth mouse lerp
            current.x += (target.x - current.x) * 0.05;
            current.y += (target.y - current.y) * 0.05;

            // Rotate knots
            knot.rotation.x  = t * 0.15 + current.y * 0.4;
            knot.rotation.y  = t * 0.22 + current.x * 0.4;
            knot2.rotation.x = -t * 0.10 + current.y * 0.25;
            knot2.rotation.y = -t * 0.17 + current.x * 0.25;

            // Rotate particle field slowly
            points.rotation.y = t * 0.03 + current.x * 0.15;
            points.rotation.x = current.y * 0.15;

            // Subtle camera breathing
            camera.position.z = 18 + Math.sin(t * 0.3) * 0.4;
            camera.lookAt(0, 0, 0);

            renderer.render(scene, camera);
            rafId = requestAnimationFrame(animate);
        }
        animate();

        // Pause when tab hidden
        document.addEventListener('visibilitychange', () => {
            if (document.hidden) cancelAnimationFrame(rafId);
            else animate();
        });
    }

    /* ============================================================
       2. TYPED ROTATOR
       ============================================================ */
    function initTyped() {
        const el = $('#mx-typed');
        if (!el) return;

        const words = JSON.parse(el.dataset.words || '[]');
        if (!words.length) return;

        const cursor = document.createElement('span');
        cursor.className = 'typed-cursor';
        cursor.textContent = '|';

        const textSpan = document.createElement('span');
        el.appendChild(textSpan);
        el.appendChild(cursor);

        let i = 0, j = 0, deleting = false;

        function tick() {
            const word = words[i];
            if (!deleting) {
                textSpan.textContent = word.slice(0, ++j);
                if (j === word.length) {
                    deleting = true;
                    return setTimeout(tick, 1600);
                }
            } else {
                textSpan.textContent = word.slice(0, --j);
                if (j === 0) {
                    deleting = false;
                    i = (i + 1) % words.length;
                }
            }
            setTimeout(tick, deleting ? 40 : 70);
        }
        tick();
    }

    /* ============================================================
       3. HEADER SHRINK + SCROLLSPY + SMOOTH SCROLL + BURGER
       ============================================================ */
    function initHeader() {
        const header = $('.mx-header');
        const navLinks = $$('.mx-nav-links a[href^="#"]');
        const sections = navLinks
            .map(a => document.getElementById(a.getAttribute('href').slice(1)))
            .filter(Boolean);

        function onScroll() {
            if (window.scrollY > 30) header.classList.add('scrolled');
            else header.classList.remove('scrolled');

            // scrollspy
            const scroll = window.scrollY + 120;
            let activeId = null;
            sections.forEach(sec => {
                if (sec.offsetTop <= scroll) activeId = sec.id;
            });
            navLinks.forEach(a => {
                a.classList.toggle('active', a.getAttribute('href') === '#' + activeId);
            });
        }
        window.addEventListener('scroll', onScroll, { passive: true });
        onScroll();

        // Smooth scroll for internal links
        $$('a[href^="#"]').forEach(a => {
            a.addEventListener('click', (e) => {
                const id = a.getAttribute('href');
                if (id === '#' || id.length < 2) return;
                const target = document.querySelector(id);
                if (!target) return;
                e.preventDefault();
                const y = target.getBoundingClientRect().top + window.scrollY - 70;
                window.scrollTo({ top: y, behavior: 'smooth' });

                // close mobile nav
                const nav = $('.mx-nav-links');
                const burger = $('.mx-burger');
                if (nav && nav.classList.contains('mobile-open')) {
                    nav.classList.remove('mobile-open');
                    burger && burger.classList.remove('open');
                }
            });
        });

        // Burger
        const burger = $('.mx-burger');
        const nav = $('.mx-nav-links');
        if (burger && nav) {
            burger.addEventListener('click', () => {
                burger.classList.toggle('open');
                nav.classList.toggle('mobile-open');
            });
        }
    }

    /* ============================================================
       4. SCROLL REVEAL
       ============================================================ */
    function initReveal() {
        const els = $$('.reveal');
        if (!('IntersectionObserver' in window)) {
            els.forEach(el => el.classList.add('is-visible'));
            return;
        }
        const io = new IntersectionObserver((entries) => {
            entries.forEach(entry => {
                if (entry.isIntersecting) {
                    entry.target.classList.add('is-visible');
                    io.unobserve(entry.target);
                }
            });
        }, { threshold: 0.12, rootMargin: '0px 0px -50px 0px' });
        els.forEach(el => io.observe(el));
    }

    /* ============================================================
       5. SPOTLIGHT HOVER (service cards)
       ============================================================ */
    function initSpotlight() {
        $$('.mx-service-card').forEach(card => {
            card.addEventListener('mousemove', (e) => {
                const r = card.getBoundingClientRect();
                card.style.setProperty('--mx', ((e.clientX - r.left) / r.width  * 100) + '%');
                card.style.setProperty('--my', ((e.clientY - r.top)  / r.height * 100) + '%');
            });
        });
    }

    /* ============================================================
       6. TILT on cards (subtle 3D)
       ============================================================ */
    function initTilt() {
        if (prefersReducedMotion) return;
        $$('[data-tilt]').forEach(el => {
            const maxTilt = parseFloat(el.dataset.tilt) || 6;
            el.style.transformStyle = 'preserve-3d';
            el.addEventListener('mousemove', (e) => {
                const r = el.getBoundingClientRect();
                const px = (e.clientX - r.left) / r.width  - 0.5;
                const py = (e.clientY - r.top)  / r.height - 0.5;
                el.style.transform = `perspective(900px) rotateY(${px * maxTilt}deg) rotateX(${-py * maxTilt}deg) translateY(-6px)`;
            });
            el.addEventListener('mouseleave', () => {
                el.style.transform = '';
            });
        });
    }

    /* ============================================================
       7. MAGNETIC buttons
       ============================================================ */
    function initMagnetic() {
        if (prefersReducedMotion) return;
        $$('[data-magnetic]').forEach(el => {
            const strength = parseFloat(el.dataset.magnetic) || 0.3;
            el.addEventListener('mousemove', (e) => {
                const r = el.getBoundingClientRect();
                const mx = e.clientX - (r.left + r.width / 2);
                const my = e.clientY - (r.top  + r.height / 2);
                el.style.transform = `translate(${mx * strength}px, ${my * strength}px)`;
            });
            el.addEventListener('mouseleave', () => {
                el.style.transform = '';
            });
        });
    }

    /* ============================================================
       8. COUNTER UP + SKILL BARS (on reveal)
       ============================================================ */
    function initCounters() {
        if (!('IntersectionObserver' in window)) return;

        // Numbers
        $$('[data-count]').forEach(el => {
            const target = parseFloat(el.dataset.count);
            const duration = parseInt(el.dataset.duration || '1800', 10);
            const suffix = el.dataset.suffix || '';
            const prefix = el.dataset.prefix || '';
            let started = false;

            const io = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting && !started) {
                        started = true;
                        const start = performance.now();
                        function step(now) {
                            const t = Math.min(1, (now - start) / duration);
                            const eased = 1 - Math.pow(1 - t, 3);
                            const val = target * eased;
                            const display = Number.isInteger(target)
                                ? Math.round(val)
                                : val.toFixed(1);
                            el.textContent = prefix + display + suffix;
                            if (t < 1) requestAnimationFrame(step);
                        }
                        requestAnimationFrame(step);
                        io.unobserve(el);
                    }
                });
            }, { threshold: 0.5 });
            io.observe(el);
        });

        // Skill bars
        $$('.mx-skill-bar').forEach(bar => {
            const pct = parseFloat(bar.dataset.value || '0');
            const io = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        bar.style.width = pct + '%';
                        io.unobserve(bar);
                    }
                });
            }, { threshold: 0.3 });
            io.observe(bar);
        });
    }

    /* ============================================================
       9. MARQUEE DUPLICATION (seamless loop)
       ============================================================ */
    function initMarquee() {
        $$('.mx-marquee-track').forEach(track => {
            const clone = track.innerHTML;
            track.innerHTML = clone + clone;
        });
    }

    /* ============================================================
       BOOT
       ============================================================ */
    document.addEventListener('DOMContentLoaded', () => {
        initHeader();
        initReveal();
        initSpotlight();
        initTilt();
        initMagnetic();
        initCounters();
        initMarquee();
        initTyped();
        initWebGLHero();
    });
})();
