(function () {
  function init() {
    const cv = document.getElementById("skc");
    if (!cv) return;
    const ctx = cv.getContext("2d");

    /* ── CANVAS SIZING ──
       Width  = sky-login-card width
       Height = sky-login-card height
       Read after DOM paint via double requestAnimationFrame to get final dimensions.
       ResizeObserver keeps it in sync if card height changes later.
    */
    function resizeCanvas() {
      const card = document.getElementById("sky-login-card");
      if (!card) return;
      const w = Math.round(card.offsetWidth) || 440;
      const h = Math.round(card.offsetHeight) || 600;
      if (cv.width !== w) cv.width = w;
      if (cv.height !== h) cv.height = h;
    }

    /* Wait two frames so card.offsetHeight reflects final layout */
    requestAnimationFrame(function () {
      requestAnimationFrame(function () {
        resizeCanvas();
      });
    });
    window.addEventListener("resize", resizeCanvas);

    /* Track card height changes (font load, zoom, etc.) */
    if (typeof ResizeObserver !== "undefined") {
      const ro = new ResizeObserver(resizeCanvas);
      const card = document.getElementById("sky-login-card");
      if (card) ro.observe(card);
    }

    /* Dynamic accessors — always reflect current canvas size */
    const dim = {
      get W() {
        return cv.width;
      },
      get H() {
        return cv.height;
      },
      get CX() {
        return cv.width / 2;
      },
      get CY() {
        return cv.height / 2;
      },
    };

    /* ── 3D GEOMETRY ──
       Raw coordinates in mm, centred on AX / OZ.
       Scale (SC) applied dynamically in proj() every frame.
       X range : 64.491..151.341 = 86.85 mm   centre AX = 107.916
       Z range : 50.926..94.147  = 43.22 mm   centre OZ = 72.536
       D = half-depth of extrusion (mm)
    */
    const AX = 107.916,
      OZ = 72.536,
      D = 9;

    /* Logo is rendered in the TOP THIRD of the canvas.
       CY_LOGO = vertical centre of the logo rendering area.
       Scale fits the logo into the top portion with margin.   */
    const LOGO_ZONE = 0.42; /* logo uses top 42% of canvas height */

    function getSC() {
      const availH = dim.H * LOGO_ZONE;
      const scX = dim.W / (86.85 + D * 2);
      const scZ = availH / (43.22 + D * 2);
      return Math.min(scX, scZ) * 0.86;
    }

    /* Vertical centre of the logo zone */
    function getLogoY() {
      return (dim.H * LOGO_ZONE) / 2;
    }

    function sv(x, z) {
      return [x - AX, z - OZ];
    }

    /* Diamond (rotated square) */
    const LO = [
      sv(106.916, 51.0),
      sv(119.2, 61.8),
      sv(107.8, 74.5),
      sv(95.812, 62.842),
    ];
    /* Right quadrilateral */
    const FD = [
      sv(121.188, 63.842),
      sv(151.341, 94.147),
      sv(109.186, 94.147),
      sv(109.186, 77.044),
    ];
    /* Left quadrilateral (mirror of FD) */
    const FG = [
      sv(93.748, 64.742),
      sv(106.646, 77.044),
      sv(106.646, 94.147),
      sv(64.491, 94.147),
    ];

    /* Extrude a 2D polygon into a 3D prism.
       Returns {verts, edges}.
       Front faces: indices 0..n-1  (y = -D)
       Back  faces: indices n..2n-1 (y = +D)  */
    function extrude(pts2d) {
      const n = pts2d.length;
      const verts = [
        ...pts2d.map(([x, z]) => [x, -D, z]),
        ...pts2d.map(([x, z]) => [x, D, z]),
      ];
      const edges = [];
      for (let i = 0; i < n; i++) {
        const j = (i + 1) % n;
        edges.push([i, j, "f"]); /* front edge  */
        edges.push([i + n, j + n, "b"]); /* back edge   */
        edges.push([i, i + n, "s"]); /* side edge   */
      }
      return { verts, edges };
    }

    const shapes = [extrude(LO), extrude(FD), extrude(FG)];

    /* ── PERSPECTIVE PROJECTION ──
       SC applied here every frame so resizing is instant.
       Logo is centred on getLogoY() (top zone), not dim.CY.  */
    function proj([x, y, z]) {
      const sc = getSC();
      const s = 1.0 / (1.0 + y / 500.0);
      return [dim.CX + x * sc * s, getLogoY() + z * sc * s, s, y];
    }

    /* ── ROTATION HELPERS ── */
    function rx(p, a) {
      const c = Math.cos(a),
        s = Math.sin(a);
      return p.map(([x, y, z]) => [x, y * c - z * s, y * s + z * c]);
    }
    function ry(p, a) {
      const c = Math.cos(a),
        s = Math.sin(a);
      return p.map(([x, y, z]) => [x * c + z * s, y, -x * s + z * c]);
    }
    function rz(p, a) {
      const c = Math.cos(a),
        s = Math.sin(a);
      return p.map(([x, y, z]) => [x * c - y * s, x * s + y * c, z]);
    }

    /* ── FLUORESCENT TUBE EFFECT ──
       4-pass rendering: wide glow → mid glow → tight glow → core wire */
    function tube(x1, y1, x2, y2, bright, al) {
      ctx.beginPath();
      ctx.moveTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.strokeStyle = "rgba(100,180,255,0.05)";
      ctx.lineWidth = 20;
      ctx.globalAlpha = al * 0.55;
      ctx.stroke();

      ctx.beginPath();
      ctx.moveTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.strokeStyle = bright
        ? "rgba(60,190,255,0.20)"
        : "rgba(15,80,200,0.08)";
      ctx.lineWidth = 8;
      ctx.globalAlpha = al * 0.88;
      ctx.stroke();

      ctx.beginPath();
      ctx.moveTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.strokeStyle = bright
        ? "rgba(150,225,255,0.65)"
        : "rgba(45,120,255,0.22)";
      ctx.lineWidth = 2.4;
      ctx.globalAlpha = al;
      ctx.stroke();

      ctx.beginPath();
      ctx.moveTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.strokeStyle = bright
        ? "rgba(225,246,255,0.98)"
        : "rgba(85,165,255,0.52)";
      ctx.lineWidth = 0.65;
      ctx.globalAlpha = al;
      ctx.stroke();
    }

    /* ── CRT ARTEFACT STATE ── */
    let t = 0,
      glT = 0,
      glL = [],
      scanY = 0,
      scanOn = false,
      scanTmr = 0;
    let flickAlpha = 1.0,
      flickTarget = 1.0,
      flickTimer = 0;

    function spawnGlitch() {
      glL = [];
      const n = (2 + Math.random() * 5) | 0;
      for (let i = 0; i < n; i++)
        glL.push({
          y: (Math.random() * dim.H) | 0,
          h: (1 + Math.random() * 5) | 0,
          dx: (Math.random() - 0.5) * 26,
          a: 0.28 + Math.random() * 0.5,
        });
      glT = (3 + Math.random() * 8) | 0;
    }

    /* ── MAIN RENDER LOOP ── */
    function draw() {
      const W = dim.W,
        H = dim.H,
        CX = dim.CX;

      ctx.clearRect(0, 0, W, H);

      /* Global flicker (all shapes at once) */
      if (--flickTimer <= 0) {
        flickTarget = Math.random() < 0.06 ? 0.55 + Math.random() * 0.35 : 1.0;
        flickTimer = (2 + Math.random() * 12) | 0;
      }
      flickAlpha += (flickTarget - flickAlpha) * 0.18;

      /* Slow tilted rotation */
      const ax = t * 0.0042 + 0.2,
        ay = t * 0.0078;
      //const ax = 0;
      //ay = 0;

      const allEdges = [];

      shapes.forEach(function ({ verts, edges }) {
        let pts = verts;
        pts = rx(pts, ax);
        pts = ry(pts, ay);
        pts = rz(pts, 0.07);
        const pr = pts.map(proj);
        edges.forEach(function ([a, b, tp]) {
          allEdges.push({ pr, a, b, tp, d: (pr[a][3] + pr[b][3]) * 0.5 });
        });
      });

      /* Ambient glow centred on logo zone */
      const logoY = getLogoY();
      const g = ctx.createRadialGradient(CX, logoY, 5, CX, logoY, 100);
      g.addColorStop(0, "rgba(0,65,195," + 0.14 * flickAlpha + ")");
      g.addColorStop(1, "rgba(0,0,0,0)");
      ctx.fillStyle = g;
      ctx.globalAlpha = 1;
      ctx.fillRect(0, 0, W, H);

      /* Painter's algorithm — back to front */
      allEdges.sort(function (u, v) {
        return v.d - u.d;
      });
      allEdges.forEach(function ({ pr, a, b, tp, d }) {
        const [ax2, ay2] = pr[a],
          [bx, by] = pr[b];
        const d01 = (d + D) / (2 * D);
        const bright = tp === "f";
        const base =
          tp === "f"
            ? 0.52 + d01 * 0.46
            : tp === "b"
            ? 0.07 + d01 * 0.06
            : 0.17 + d01 * 0.22;
        tube(ax2, ay2, bx, by, bright, base * flickAlpha);
      });

      ctx.globalAlpha = 1;

      /* Glitch: horizontal band shifts + compression block artefacts */
      if (glT > 0) {
        glT--;
        glL.forEach(function (gl) {
          try {
            const sl = ctx.getImageData(0, gl.y, W, gl.h);
            ctx.globalAlpha = gl.a;
            ctx.putImageData(sl, gl.dx, gl.y);
          } catch (e) {}
          ctx.fillStyle = "rgba(0,150,255,0.04)";
          ctx.globalAlpha = 1;
          ctx.fillRect(0, gl.y, W, gl.h);
        });
        if (Math.random() < 0.4) {
          ctx.globalAlpha = 0.08;
          ctx.fillStyle = "#00eeff";
          ctx.fillRect(0, (Math.random() * H) | 0, W, 1);
        }
        if (Math.random() < 0.25) {
          ctx.globalAlpha = 0.12;
          ctx.fillStyle = "rgba(0,80,220,0.5)";
          ctx.fillRect(
            (Math.random() * (W - 40)) | 0,
            (Math.random() * (H - 8)) | 0,
            (18 + Math.random() * 38) | 0,
            (2 + Math.random() * 7) | 0
          );
        }
      }

      /* Rolling scan line */
      if (scanOn) {
        ctx.globalAlpha = 0.06;
        ctx.fillStyle = "rgba(80,200,255,1)";
        ctx.fillRect(0, scanY, W, 2);
        scanY = (scanY + 3) % H;
        if (--scanTmr <= 0) scanOn = false;
      }

      /* Phosphor burn (persistence) */
      if (Math.random() < 0.016) {
        ctx.globalAlpha = 0.025;
        ctx.fillStyle = "rgba(0,120,255,1)";
        ctx.fillRect(
          (CX - 50 + Math.random() * 100) | 0,
          (logoY - 30 + Math.random() * 60) | 0,
          (Math.random() * 25) | 0,
          1
        );
      }

      ctx.globalAlpha = 1;

      /* Random artefact triggers */
      if (Math.random() < 0.012) spawnGlitch();
      if (Math.random() < 0.006) {
        scanOn = true;
        scanY = 0;
        scanTmr = (20 + Math.random() * 30) | 0;
      }

      t++;

      requestAnimationFrame(draw);
    }

    draw();
  } /* end init() */

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();

/* ── BRIDGE: Skynet UI → hidden Roundcube form ── */
document.addEventListener("DOMContentLoaded", function () {
  /* Detect Roundcube auth error and show Skynet error box */
  const rcError = document.querySelector(
    "#messagestack .alert-warning, #messagestack .alert-danger, #messagestack .alert"
  );
  if (rcError && rcError.textContent.trim() !== "") {
    const skyError = document.getElementById("sky-error");
    skyError.textContent = "⚠  AUTHENTIFICATION REFUSÉE — ACCÈS INTERDIT";
    skyError.classList.add("visible");
    const card = document.getElementById("sky-login-card");
    card.style.borderColor = "rgba(255,68,68,0.5)";
    card.style.boxShadow = "0 0 30px rgba(255,68,68,0.1)";
    const ms = document.getElementById("messagestack");
    if (ms) ms.style.display = "none";
  }

  /* Submit handler: copy values then submit real RC form */
  document
    .getElementById("sky-submit-btn")
    .addEventListener("click", function () {
      const user = document.getElementById("sky-user").value.trim();
      const pass = document.getElementById("sky-pass").value;

      if (!user || !pass) {
        document.getElementById("sky-error").textContent =
          "⚠  IDENTIFIANTS MANQUANTS";
        document.getElementById("sky-error").classList.add("visible");
        return;
      }

      const rcUser =
        document.getElementById("rcmloginuser") ||
        document.querySelector('#login-form input[name="_user"]');
      const rcPass =
        document.getElementById("rcmloginpwd") ||
        document.querySelector('#login-form input[name="_pass"]');

      if (rcUser) rcUser.value = user;
      if (rcPass) rcPass.value = pass;

      const btn = document.getElementById("sky-submit-btn");
      btn.textContent = "AUTHENTIFICATION...";
      btn.style.borderColor = "var(--cyan)";
      btn.style.color = "var(--cyan)";

      const rcForm = document.getElementById("login-form");
      if (rcForm) {
        rcForm.style.display = "block";
        rcForm.submit();
      }
    });

  /* Submit on Enter key */
  ["sky-user", "sky-pass"].forEach(function (id) {
    document.getElementById(id).addEventListener("keydown", function (e) {
      if (e.key === "Enter") document.getElementById("sky-submit-btn").click();
    });
  });

  /* Auto-focus username field */
  document.getElementById("sky-user").focus();
});

/* ── FULLSCREEN PARTICLE BACKGROUND ── */
const canvas = document.getElementById("bg-canvas");
const ctx = canvas.getContext("2d");

function resize() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
}
resize();
window.addEventListener("resize", resize);

const particles = [];
for (let i = 0; i < 80; i++) {
  particles.push({
    x: Math.random() * window.innerWidth,
    y: Math.random() * window.innerHeight,
    vx: (Math.random() - 0.5) * 0.4,
    vy: -Math.random() * 0.6 - 0.1,
    r: Math.random() * 1.5 + 0.5,
    alpha: Math.random() * 0.5 + 0.1,
    color: Math.random() > 0.5 ? "#1a6fff" : "#00aaff",
  });
}

const streams = [];
for (let i = 0; i < 14; i++) {
  streams.push({
    x: Math.random() * window.innerWidth,
    y: Math.random() * window.innerHeight,
    speed: Math.random() * 1.5 + 0.5,
    length: Math.random() * 80 + 40,
    alpha: Math.random() * 0.15 + 0.05,
  });
}

function drawBg() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  /* Data streams */
  streams.forEach(function (s) {
    const grad = ctx.createLinearGradient(s.x, s.y - s.length, s.x, s.y);
    grad.addColorStop(0, "rgba(26,111,255,0)");
    grad.addColorStop(1, "rgba(0,170,255," + s.alpha + ")");
    ctx.strokeStyle = grad;
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(s.x, s.y - s.length);
    ctx.lineTo(s.x, s.y);
    ctx.stroke();
    s.y += s.speed;
    if (s.y > canvas.height + s.length) {
      s.y = -s.length;
      s.x = Math.random() * canvas.width;
    }
  });

  /* Floating particles */
  particles.forEach(function (p) {
    ctx.beginPath();
    ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
    ctx.fillStyle = p.color;
    ctx.globalAlpha = p.alpha;
    ctx.fill();
    ctx.globalAlpha = 1;
    p.x += p.vx;
    p.y += p.vy;
    if (p.y < -5) {
      p.y = canvas.height + 5;
      p.x = Math.random() * canvas.width;
    }
    if (p.x < -5) p.x = canvas.width + 5;
    if (p.x > canvas.width + 5) p.x = -5;
  });

  /* Connection lines between nearby particles */
  for (let i = 0; i < particles.length; i++) {
    for (let j = i + 1; j < particles.length; j++) {
      const dx = particles[i].x - particles[j].x;
      const dy = particles[i].y - particles[j].y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      if (dist < 100) {
        ctx.globalAlpha = (1 - dist / 100) * 0.3;
        ctx.lineWidth = 0.5;
        ctx.strokeStyle = "#00cfff";
        ctx.beginPath();
        ctx.moveTo(particles[i].x, particles[i].y);
        ctx.lineTo(particles[j].x, particles[j].y);
        ctx.stroke();
        ctx.globalAlpha = 1;
      }
    }
  }
  requestAnimationFrame(drawBg);
}
drawBg();
