/* ============================================
   ZENVYROLABS 2026 — JavaScript
   Canvas · Scroll Reveal · Timeline Fill · Nav
   ============================================ */

(function () {
    'use strict';

    /* ADDED — touch device detection */
    const isTouch = window.matchMedia('(hover: none)').matches || 'ontouchstart' in window;
    const isMobile = window.innerWidth < 768;

    /* ---- SCROLL REVEAL ---- */
    function initScrollReveal() {
        const els = document.querySelectorAll('.sr, .sr-children, .sr-scale');
        if (!els.length) return;
        const io = new IntersectionObserver(
            (entries) => {
                entries.forEach((e) => {
                    if (e.isIntersecting) {
                        e.target.classList.add('in-view');
                        io.unobserve(e.target);
                    }
                });
            },
            { threshold: 0.1, rootMargin: '0px 0px -60px 0px' }
        );
        els.forEach((el) => io.observe(el));
    }

    /* ---- HEADER SCROLL ---- */
    function initHeaderScroll() {
        const header = document.getElementById('site-header');
        if (!header) return;
        let raf = false;
        window.addEventListener(
            'scroll',
            () => {
                if (!raf) {
                    requestAnimationFrame(() => {
                        header.classList.toggle('scrolled', window.scrollY > 50);
                        raf = false;
                    });
                    raf = true;
                }
            },
            { passive: true }
        );
    }

    /* ---- MOBILE NAV ---- */
    function initMobileNav() {
        const hamburger = document.querySelector('.hamburger');
        const mobileNav = document.querySelector('.mobile-nav');
        const closeBtn = document.querySelector('.close-btn');

        if (!hamburger || !mobileNav) return;

        hamburger.addEventListener('click', () => {
            mobileNav.classList.add('active');
            document.body.classList.add('nav-open');
        });

        if (closeBtn) {
            closeBtn.addEventListener('click', () => {
                mobileNav.classList.remove('active');
                document.body.classList.remove('nav-open');
            });
        }

        // Close nav when clicking a link
        mobileNav.querySelectorAll('a').forEach((a) => {
            a.addEventListener('click', () => {
                mobileNav.classList.remove('active');
                document.body.classList.remove('nav-open');
            });
        });
    }

    /* ---- SMOOTH SCROLL ---- */
    function initSmoothScroll() {
        document.querySelectorAll('a[href^="#"]').forEach((a) => {
            a.addEventListener('click', (e) => {
                const id = a.getAttribute('href');
                if (id === '#') return;
                const target = document.querySelector(id);
                if (target) {
                    e.preventDefault();
                    const headerH = document.getElementById('site-header')?.offsetHeight || 0;
                    const y = target.getBoundingClientRect().top + window.scrollY - headerH - 20;
                    window.scrollTo({ top: y, behavior: 'smooth' });
                }
            });
        });
    }

    /* ---- THREE.JS BACKGROUND ARCHITECT ---- */
    function initThreeBackgrounds() {
        setupManager();

        function setupManager() {
            const bgs = document.querySelectorAll('.section-bg');
            const activeScenes = new Map();

            let mouse = new THREE.Vector2(0, 0);
            let scrollVelocity = 0;
            let lastScrollY = window.scrollY;

            window.addEventListener('mousemove', (e) => {
                mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
                mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
            });

            window.addEventListener('scroll', () => {
                scrollVelocity = Math.abs(window.scrollY - lastScrollY);
                lastScrollY = window.scrollY;
            }, { passive: true });

            const observer = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        createScene(entry.target);
                    } else {
                        destroyScene(entry.target);
                    }
                });
            }, { threshold: 0.1 });

            bgs.forEach(bg => observer.observe(bg));

            window.addEventListener('resize', () => {
                activeScenes.forEach((data, id) => {
                    const el = document.getElementById(id);
                    data.renderer.setSize(el.clientWidth, el.clientHeight);
                    // Also update camera aspect
                    const camera = data.scene.children.find(c => c.isPerspectiveCamera);
                    if (camera) {
                        camera.aspect = el.clientWidth / el.clientHeight;
                        camera.updateProjectionMatrix();
                    }
                });
            });

            function createScene(container) {
                if (activeScenes.has(container.id)) return;

                const type = container.dataset.bg;
                const scene = new THREE.Scene();
                const camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000);
                const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
                renderer.setSize(container.clientWidth, container.clientHeight);
                renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
                container.appendChild(renderer.domElement);

                const objects = [];
                let frameId = null;

                // Logic per type
                if (type === 'mesh') {
                    const meshDetail = isMobile ? 18 : 30; /* ADDED — reduce mesh detail on mobile */
                    const geometry = new THREE.PlaneGeometry(25, 25, meshDetail, meshDetail);
                    const material = new THREE.MeshBasicMaterial({ color: 0x00c6ff, wireframe: true, transparent: true, opacity: 0.15 });
                    const mesh = new THREE.Mesh(geometry, material);
                    mesh.rotation.x = -Math.PI / 2.5;
                    scene.add(mesh);
                    objects.push(mesh);
                }
                else if (type === 'blobs') {
                    const blobCount = isMobile ? 3 : 6; /* ADDED — reduce on mobile */
                    for (let i = 0; i < blobCount; i++) {
                        const geometry = new THREE.SphereGeometry(Math.random() * 1.5 + 0.5, 32, 32);
                        const material = new THREE.MeshPhongMaterial({ color: 0x00c6ff, transparent: true, opacity: 0.1 });
                        const blob = new THREE.Mesh(geometry, material);
                        blob.position.set((Math.random() - 0.5) * 15, (Math.random() - 0.5) * 10, (Math.random() - 0.5) * 5);
                        scene.add(blob);
                        objects.push({ mesh: blob, vel: new THREE.Vector3((Math.random() - 0.5) * 0.01, (Math.random() - 0.5) * 0.01, 0) });
                    }
                    const pLight = new THREE.PointLight(0xffffff, 1, 100);
                    pLight.position.set(5, 5, 5);
                    scene.add(pLight);
                    scene.add(new THREE.AmbientLight(0x404040));
                }
                else if (type === 'grid') {
                    const group = new THREE.Group();
                    for (let i = 0; i < 15; i++) {
                        const geometry = new THREE.BoxGeometry(0.8, 0.8, 0.8);
                        const material = new THREE.MeshBasicMaterial({ color: 0x00c6ff, wireframe: true, transparent: true, opacity: 0.15 });
                        const cube = new THREE.Mesh(geometry, material);
                        cube.position.set((Math.random() - 0.5) * 20, (Math.random() - 0.5) * 15, (Math.random() - 0.5) * 10);
                        group.add(cube);
                    }
                    scene.add(group);
                    objects.push(group);
                }
                else if (type === 'streams') {
                    const streamCount = isMobile ? 40 : 100; /* ADDED — reduce on mobile */
                    for (let i = 0; i < streamCount; i++) {
                        const geometry = new THREE.BufferGeometry();
                        const pos = new Float32Array([0, 0, 0, 0, (Math.random() * 2 + 1), 0]);
                        geometry.setAttribute('position', new THREE.BufferAttribute(pos, 3));
                        const mat = new THREE.LineBasicMaterial({ color: 0x00c6ff, transparent: true, opacity: 0.1 });
                        const line = new THREE.Line(geometry, mat);
                        line.position.set((Math.random() - 0.5) * 30, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 10);
                        scene.add(line);
                        objects.push({ mesh: line, speed: Math.random() * 0.05 + 0.02 });
                    }
                }
                else if (type === 'constellation') {
                    const count = isMobile ? 25 : 60; /* ADDED — reduce on mobile */
                    const geometry = new THREE.BufferGeometry();
                    const pos = new Float32Array(count * 3);
                    for (let i = 0; i < count * 3; i++) pos[i] = (Math.random() - 0.5) * 25;
                    geometry.setAttribute('position', new THREE.BufferAttribute(pos, 3));
                    const material = new THREE.PointsMaterial({ color: 0x00c6ff, size: 0.15, transparent: true, opacity: 0.6 });
                    const points = new THREE.Points(geometry, material);
                    scene.add(points);
                    const lines = new THREE.LineSegments(geometry, new THREE.LineBasicMaterial({ color: 0x00c6ff, transparent: true, opacity: 0.1 }));
                    scene.add(lines);
                    objects.push(points, lines);
                }
                else if (type === 'prisms') {
                    for (let i = 0; i < 10; i++) {
                        const geometry = new THREE.TetrahedronGeometry(Math.random() * 1.5 + 0.5);
                        const material = new THREE.MeshBasicMaterial({ color: 0x00c6ff, wireframe: true, transparent: true, opacity: 0.2 });
                        const prism = new THREE.Mesh(geometry, material);
                        prism.position.set((Math.random() - 0.5) * 25, (Math.random() - 0.5) * 15, (Math.random() - 0.5) * 10);
                        scene.add(prism);
                        objects.push(prism);
                    }
                }
                else if (type === 'spheres') {
                    const group = new THREE.Group();
                    for (let i = 0; i < 20; i++) {
                        const geometry = new THREE.SphereGeometry(0.2, 16, 16);
                        const material = new THREE.MeshBasicMaterial({ color: 0x00c6ff, transparent: true, opacity: 0.4 });
                        const sphere = new THREE.Mesh(geometry, material);
                        const angle = Math.random() * Math.PI * 2;
                        const radius = Math.random() * 8 + 2;
                        sphere.position.set(Math.cos(angle) * radius, Math.sin(angle) * radius, (Math.random() - 0.5) * 5);
                        group.add(sphere);
                    }
                    scene.add(group);
                    objects.push(group);
                }
                else if (type === 'vortex') {
                    const count = isMobile ? 500 : 1500; /* ADDED — reduce on mobile */
                    const geometry = new THREE.BufferGeometry();
                    const pos = new Float32Array(count * 3);
                    for (let i = 0; i < count; i++) {
                        const r = Math.random() * 10 + 2;
                        const theta = Math.random() * Math.PI * 2;
                        pos[i * 3] = r * Math.cos(theta);
                        pos[i * 3 + 1] = (Math.random() - 0.5) * 20;
                        pos[i * 3 + 2] = r * Math.sin(theta);
                    }
                    geometry.setAttribute('position', new THREE.BufferAttribute(pos, 3));
                    const material = new THREE.PointsMaterial({ color: 0x00c6ff, size: 0.05, transparent: true, opacity: 0.4 });
                    const vortex = new THREE.Points(geometry, material);
                    scene.add(vortex);
                    objects.push(vortex);
                }

                camera.position.z = 10;

                function animate(time) {
                    frameId = requestAnimationFrame(animate);

                    // Velocity decay
                    if (scrollVelocity > 0.1) scrollVelocity *= 0.95;
                    else scrollVelocity = 0;

                    const vOffset = Math.min(scrollVelocity * 0.05, 5.0);

                    if (type === 'mesh') {
                        const posArray = objects[0].geometry.attributes.position.array;
                        const waveAmp = 0.5 + Math.min(scrollVelocity * 0.02, 2.0);
                        for (let i = 0; i < posArray.length; i += 3) {
                            const x = posArray[i];
                            const y = posArray[i + 1];
                            posArray[i + 2] = Math.sin(time * 0.001 + x * 0.5 + y * 0.5) * waveAmp;
                        }
                        objects[0].geometry.attributes.position.needsUpdate = true;
                        objects[0].rotation.y = mouse.x * 0.1 + vOffset * 0.1;
                        objects[0].rotation.x = -Math.PI / 2.5 + mouse.y * 0.05;
                    }
                    else if (type === 'blobs') {
                        objects.forEach(b => {
                            const speedMulti = 1 + vOffset;
                            b.mesh.position.add(b.vel.clone().multiplyScalar(speedMulti));
                            if (Math.abs(b.mesh.position.x) > 10) b.vel.x *= -1;
                            if (Math.abs(b.mesh.position.y) > 8) b.vel.y *= -1;
                            b.mesh.rotation.x += 0.005 * speedMulti;
                        });
                        scene.position.x = mouse.x * 2;
                        scene.position.y = mouse.y * 2;
                    }
                    else if (type === 'grid') {
                        objects[0].rotation.y += 0.002 + mouse.x * 0.05 + vOffset * 0.02;
                        objects[0].rotation.x += 0.001 + mouse.y * 0.05 + vOffset * 0.02;
                        objects[0].position.z = vOffset > 0 ? Math.min(vOffset * 2, 5) : 0;
                        objects[0].position.x = mouse.x * 3;
                        objects[0].position.y = mouse.y * 3;
                    }
                    else if (type === 'streams') {
                        objects.forEach(s => {
                            s.mesh.position.y -= (s.speed + vOffset * 0.05);
                            if (s.mesh.position.y < -15) s.mesh.position.y = 15;
                            s.mesh.rotation.z = mouse.x * 0.1;
                        });
                    }
                    else if (type === 'constellation') {
                        objects.forEach(o => {
                            o.rotation.y += 0.0015 + vOffset * 0.01;
                            o.rotation.x = mouse.y * 0.4;
                            o.rotation.z = mouse.x * 0.4;
                            o.position.x = mouse.x * 2;
                            o.position.y = mouse.y * 2;
                        });
                    }
                    else if (type === 'prisms') {
                        objects.forEach(p => {
                            p.rotation.x += 0.01 + vOffset * 0.02;
                            p.rotation.y += 0.01 + vOffset * 0.02;
                            p.position.x += mouse.x * 0.05;
                        });
                    }
                    else if (type === 'spheres') {
                        objects[0].rotation.z += 0.005 + vOffset * 0.02;
                        objects[0].rotation.x = mouse.y * 0.5;
                        objects[0].rotation.y = mouse.x * 0.5;
                    }
                    else if (type === 'vortex') {
                        objects[0].rotation.y += 0.005 + mouse.x * 0.05 + vOffset * 0.02;
                        objects[0].rotation.x = mouse.y * 0.5;
                    }

                    renderer.render(scene, camera);
                }

                animate(0);
                activeScenes.set(container.id, { renderer, scene, frameId });
            }

            function destroyScene(container) {
                const data = activeScenes.get(container.id);
                if (!data) return;
                cancelAnimationFrame(data.frameId);
                data.renderer.dispose();
                container.innerHTML = '';
                activeScenes.delete(container.id);
            }

            window.addEventListener('resize', () => {
                activeScenes.forEach((data, id) => {
                    const el = document.getElementById(id);
                    if (!el) return;
                    data.renderer.setSize(el.clientWidth, el.clientHeight);
                    const camera = data.scene.children.find(c => c.isPerspectiveCamera);
                    if (camera) {
                        camera.aspect = el.clientWidth / el.clientHeight;
                        camera.updateProjectionMatrix();
                    }
                });
            });
        }
    }

    /* ---- TIMELINE SCROLL FILL ---- */
    function initTimelineFill() {
        const container = document.getElementById('timeline-container');
        const fill = document.getElementById('timeline-fill');
        if (!container || !fill) return;

        const nodes = container.querySelectorAll('.timeline-node');
        const track = container.querySelector('.timeline-track');

        function update() {
            const containerRect = container.getBoundingClientRect();
            const trackRect = track.getBoundingClientRect();
            const viewportCenter = window.innerHeight * 0.6;

            // Calculate how far the user has scrolled through the timeline
            const trackTop = trackRect.top;
            const trackHeight = trackRect.height;
            const scrolled = viewportCenter - trackTop;
            const progress = Math.max(0, Math.min(1, scrolled / trackHeight));

            fill.style.height = (progress * 100) + '%';

            // Activate nodes based on scroll position
            nodes.forEach((node) => {
                const nodeRect = node.getBoundingClientRect();
                const nodeCenter = nodeRect.top + nodeRect.height * 0.3;
                if (nodeCenter < viewportCenter) {
                    node.classList.add('active');
                } else {
                    node.classList.remove('active');
                }
            });

            requestAnimationFrame(update);
        }

        requestAnimationFrame(update);
    }

    /* ---- CONTACT FORM ---- */
    function initContact() {
        const form = document.getElementById('contact-form');
        if (!form) return;
        form.addEventListener('submit', (e) => {
            e.preventDefault();
            const name = form.querySelector('#c-name').value.trim();
            const email = form.querySelector('#c-email').value.trim();
            const subject = form.querySelector('#c-subject').value.trim() || 'Project Inquiry';
            const message = form.querySelector('#c-message').value.trim();
            if (!name || !email || !message) return;

            const subj = encodeURIComponent(`${subject} — from ${name}`);
            const body = encodeURIComponent(`Name: ${name}\nEmail: ${email}\n\n${message}`);
            window.location.href = `mailto:zenvyrolabs77@gmail.com?subject=${subj}&body=${body}`;

            const btn = form.querySelector('.form-submit');
            btn.textContent = 'Opening email client...';
            btn.style.opacity = '0.6';
            setTimeout(() => {
                btn.textContent = 'Send Message';
                btn.style.opacity = '1';
            }, 3000);
        });
    }

    /* ---- MAGNETIC HOVER EFFECT ON CARDS ---- */
    function initMagnetic() {
        if (isTouch) return; /* ADDED — skip on touch devices */
        const cards = document.querySelectorAll('.why-card');
        cards.forEach((card) => {
            card.addEventListener('mousemove', (e) => {
                const rect = card.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const y = e.clientY - rect.top;
                const cx = rect.width / 2;
                const cy = rect.height / 2;
                const moveX = ((x - cx) / cx) * 4;
                const moveY = ((y - cy) / cy) * 4;
                card.style.transform = `translateY(-8px) rotateX(${-moveY}deg) rotateY(${moveX}deg)`;
            });
            card.addEventListener('mouseleave', () => {
                card.style.transform = '';
            });
        });
    }

    /* ---- COUNTER ANIMATION ---- */
    function initCounters() {
        const stats = document.querySelectorAll('.stat-value');
        if (!stats.length) return;

        const io = new IntersectionObserver(
            (entries) => {
                entries.forEach((e) => {
                    if (e.isIntersecting) {
                        animateCounter(e.target);
                        io.unobserve(e.target);
                    }
                });
            },
            { threshold: 0.5 }
        );
        stats.forEach((s) => io.observe(s));

        function animateCounter(el) {
            const text = el.textContent.trim();
            const match = text.match(/^(\d+)/);
            if (!match) return;
            const target = parseInt(match[1], 10);
            const suffix = text.replace(/^\d+/, '');
            const duration = 1200;
            const start = performance.now();

            function step(now) {
                const elapsed = now - start;
                const progress = Math.min(elapsed / duration, 1);
                const ease = 1 - Math.pow(1 - progress, 3); // ease-out cubic
                const current = Math.round(target * ease);
                el.textContent = current + suffix;
                if (progress < 1) requestAnimationFrame(step);
            }
            requestAnimationFrame(step);
        }
    }

    /* ---- VISITOR TRACKING (HIDDEN) ---- */
    function initVisitorTracking() {
        // Basic local tracking system (for demonstration/local use).
        // In a real production environment, this would require a backend database.
        let visits = localStorage.getItem('_zvl_v_count') || 0;

        // Check if this is a new session (rudimentary check using sessionStorage)
        if (!sessionStorage.getItem('_zvl_session_active')) {
            visits = parseInt(visits, 10) + 1;
            localStorage.setItem('_zvl_v_count', visits);
            sessionStorage.setItem('_zvl_session_active', 'true');
        }

        // Expose a hidden global function for the owner to check stats
        // The owner can open the browser console (F12) and type: zenvyro_stats()
        window.zenvyro_stats = function () {
            console.log(`%c[ZenvyroLabs Admin] Total recorded visits: ${visits}`, 'color: #00c6ff; font-weight: bold; font-size: 14px;');
            return visits;
        };
    }

    /* ---- TEXT ROTATORS (TYPEWRITER) ---- */
    function initTextRotators() {
        const createTypewriter = (id, phrases) => {
            const el = document.getElementById(id);
            if (!el) return;

            let phraseIdx = 0;
            let charIdx = 0;
            let isDeleting = false;
            let delay = 60;

            function tick() {
                const fullTxt = phrases[phraseIdx];

                if (isDeleting) {
                    el.textContent = fullTxt.substring(0, charIdx - 1);
                    charIdx--;
                    delay = 30; // Faster backspacing
                } else {
                    el.textContent = fullTxt.substring(0, charIdx + 1);
                    charIdx++;
                    delay = 70; // Natural typing
                }

                if (!isDeleting && charIdx === fullTxt.length) {
                    isDeleting = true;
                    delay = 2000; // Look at the finished phrase for 2s
                } else if (isDeleting && charIdx === 0) {
                    isDeleting = false;
                    phraseIdx = (phraseIdx + 1) % phrases.length;
                    delay = 500; // Pause before typing next
                }

                setTimeout(tick, delay);
            }

            tick();
        };

        createTypewriter('why-rotator', [
            "We do not just write code.",
            "We engineer products that work.",
            "We build for infinite scale.",
            "We deliver measurable results."
        ]);

        createTypewriter('hero-rotator', [
            "We design and build production-grade web platforms.",
            "We engineer high-performance mobile applications.",
            "We build complex institutional systems.",
            "From architecture to deployment — engineered for the real world."
        ]);
    }

    /* ---- INIT ---- */
    document.addEventListener('DOMContentLoaded', () => {
        initScrollReveal();
        initHeaderScroll();
        initMobileNav();
        initSmoothScroll();
        initThreeBackgrounds();
        initTimelineFill();
        initContact();
        initMagnetic();
        initCounters();
        initVisitorTracking();
        initTextRotators();

        /* ADDED — disable custom cursor on touch devices */
        if (isTouch) {
            const cursor = document.querySelector('.scanner-cursor');
            if (cursor) cursor.style.display = 'none';
            document.documentElement.style.cursor = 'auto';
            document.body.style.cursor = 'auto';
        }
    });
})();
