// ── Typewriter ───────────────────────────────────────────
(function () {
    const el    = document.getElementById('typewriter');
    const words = ['Entwickler', 'Schüler', 'Macher', 'Selfhoster', 'Tüftler'];
    let wi = 0, ci = 0, deleting = false;

    function type() {
        if (!el) return;
        const word = words[wi];
        el.textContent = deleting ? word.slice(0, ci--) : word.slice(0, ci++);

        let delay = deleting ? 60 : 110;
        if (!deleting && ci > word.length)  { delay = 1400; deleting = true; }
        if  (deleting && ci < 0)            { deleting = false; wi = (wi + 1) % words.length; ci = 0; delay = 300; }
        setTimeout(type, delay);
    }
    setTimeout(type, 900);
})();

// ── Particles ────────────────────────────────────────────
(function () {
    const canvas = document.getElementById('particle-canvas');
    if (!canvas) return;
    const ctx    = canvas.getContext('2d');
    const COLORS = ['#6366f1', '#0ea5e9', '#a855f7', '#ec4899', '#22d3ee'];
    let W, H, particles = [];

    function resize() { W = canvas.width = window.innerWidth; H = canvas.height = window.innerHeight; }
    function rand(a, b) { return Math.random() * (b - a) + a; }

    function mkP() {
        return { x: rand(0,W), y: rand(0,H), r: rand(0.8,2.2), dx: rand(-0.25,0.25), dy: rand(-0.35,-0.08),
            alpha: rand(0.2,0.8), fade: rand(0.002,0.006), color: COLORS[Math.floor(Math.random()*COLORS.length)] };
    }

    function init() { resize(); particles = Array.from({length:90}, mkP); }

    function draw() {
        ctx.clearRect(0, 0, W, H);
        for (let p of particles) {
            ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, Math.PI*2);
            ctx.fillStyle = p.color; ctx.globalAlpha = p.alpha; ctx.fill();
            p.x += p.dx; p.y += p.dy; p.alpha -= p.fade;
            if (p.alpha <= 0 || p.y < -5) Object.assign(p, mkP(), { y: H+5, alpha: rand(0.2,0.7) });
        }
        ctx.globalAlpha = 1;
        requestAnimationFrame(draw);
    }

    window.addEventListener('resize', resize);
    init(); draw();
})();

// ── 3D Tilt Cards ────────────────────────────────────────
document.querySelectorAll('.card').forEach(card => {
    card.addEventListener('mousemove', function (e) {
        const rect   = this.getBoundingClientRect();
        const cx     = rect.left + rect.width  / 2;
        const cy     = rect.top  + rect.height / 2;
        const dx     = (e.clientX - cx) / (rect.width  / 2);
        const dy     = (e.clientY - cy) / (rect.height / 2);
        const rotX   = (-dy * 8).toFixed(2);
        const rotY   = ( dx * 8).toFixed(2);
        this.style.transform = `perspective(600px) rotateX(${rotX}deg) rotateY(${rotY}deg) translateY(-3px) scale(1.02)`;

        // glare
        let glare = this.querySelector('.card-glare');
        if (!glare) {
            glare = document.createElement('div');
            glare.className = 'card-glare';
            this.appendChild(glare);
        }
        const gx = ((e.clientX - rect.left) / rect.width  * 100).toFixed(1);
        const gy = ((e.clientY - rect.top)  / rect.height * 100).toFixed(1);
        glare.style.background = `radial-gradient(circle at ${gx}% ${gy}%, rgba(255,255,255,0.12) 0%, transparent 65%)`;
    });

    card.addEventListener('mouseleave', function () {
        this.style.transform = '';
        this.querySelector('.card-glare')?.remove();
    });

    // Ripple
    card.addEventListener('click', function (e) {
        const circle   = document.createElement('span');
        const diameter = Math.max(this.clientWidth, this.clientHeight);
        const rect     = this.getBoundingClientRect();
        circle.classList.add('ripple');
        circle.style.width = circle.style.height = diameter + 'px';
        circle.style.left = (e.clientX - rect.left - diameter / 2) + 'px';
        circle.style.top  = (e.clientY - rect.top  - diameter / 2) + 'px';
        this.querySelector('.ripple')?.remove();
        this.appendChild(circle);
    });
});

// ── Server Status Badges (async, no reload) ───────────────
(async function () {
    const cards = Array.from(document.querySelectorAll('.card[data-status-url]'));
    if (cards.length === 0) return;

    const endpoint = '/api/server_status.php';

    const normalize = (url) => {
        if (!url) return '';
        return String(url).replace(/\/+$/, '');
    };

    const safeJsonParse = (text) => {
        const cleaned = String(text || '')
            .replace(/^\uFEFF/, '')
            .replace(/\u0000/g, '')
            .trim();
        if (!cleaned) return null;
        return JSON.parse(cleaned);
    };

    const apply = (byUrl) => {
        for (const card of cards) {
            const key = normalize(card.getAttribute('data-status-url'));
            const svc = byUrl[key] || byUrl[key + '/'] || null;
            if (!svc) continue;

            const badge = card.querySelector('[data-status-badge="1"]');
            if (!badge) continue;

            const state = svc.state || 'unknown';
            badge.classList.remove('status-badge--unknown', 'status-badge--up', 'status-badge--down');
            badge.classList.add('status-badge--' + state);

            if (state === 'up') {
                badge.textContent = 'Online';
                badge.title = 'Online';
            } else if (state === 'down') {
                badge.textContent = 'Offline';
                badge.title = svc.detail || 'Offline';
            } else {
                badge.textContent = 'Lädt...';
                badge.title = svc.detail || 'Lädt...';
            }
        }
    };

    // Exactly ~1s delay, then fetch.
    await new Promise(r => setTimeout(r, 1000));

    try {
        const res = await fetch(endpoint, { cache: 'no-store' });
        if (!res.ok) return;

        const text = await res.text();
        const payload = safeJsonParse(text);
        if (!payload || !payload.byUrlNormalized) return;

        apply(payload.byUrlNormalized);
    } catch (e) {
        // keep "Lädt..."
    }
})();
