// LanDocs promo — v2 timing. Apple-ad structure:
//   each scene is preceded by a full-screen title card (~1.3s), then a clean
//   demo beat, then a small breath before the next title card. The user
//   always knows what they're about to see before the UI starts moving.

const Times = {
  // ── Act 1 · Cold open ──────────────────────────────────────────────────
  introStart:    0.0,
  introEnd:      3.50,   // brand wordmark fades out, white frame ready

  // ── Act 2 · DRAG ───────────────────────────────────────────────────────
  cardA_in:      3.50,
  cardA_out:     4.80,   // "Drag. Drop. Done." holds 4.80–4.80
  dragStart:     4.80,
  dragEnd:       8.00,

  // ── Act 3 · POPULATE ───────────────────────────────────────────────────
  cardB_in:      8.00,
  cardB_out:     9.30,
  populateStart: 9.30,
  populateEnd:   12.50,

  // ── Act 4 · CONNECT ────────────────────────────────────────────────────
  cardC_in:     12.50,
  cardC_out:    13.80,
  connectStart: 13.80,
  connectEnd:   17.30,

  // ── Act 5 · CONFIGURE ──────────────────────────────────────────────────
  cardD_in:     17.30,
  cardD_out:    18.50,
  propsStart:   18.50,
  propsEnd:     21.80,

  // ── Act 6 · AI ─────────────────────────────────────────────────────────
  cardE_in:     21.80,
  cardE_out:    23.10,
  aiStart:      23.10,
  aiEnd:        27.30,

  // ── Act 7 · Outro (held long) ──────────────────────────────────────────
  outroStart:   27.30,
  outroEnd:     33.50,
};

const TOTAL = 33.50;

// Stage size
const W = 1920;
const H = 1080;

// Canvas device positions (stage-absolute — top-left = 0,0 of the .ld-app).
const DEVICE_LAYOUT = {
  router:  { x: 850, y: 200, w: 220, h: 130 },
  switch:  { x: 800, y: 430, w: 320, h: 150 },
  server:  { x: 520, y: 720, w: 200, h: 110 },
  pc1:     { x: 820, y: 720, w: 200, h: 110 },
  pc2:     { x: 1120, y: 720, w: 200, h: 110 },
};

const DEVICE_INFO = {
  router: { type: 'router', name: 'Edge Router',  ports: 6,  ip: '192.168.1.1'   },
  switch: { type: 'switch', name: 'Core Switch',  ports: 24, ip: '192.168.1.10'  },
  server: { type: 'server', name: 'NAS',          ports: 2,  ip: '192.168.1.20'  },
  pc1:    { type: 'pc',     name: 'Workstation',  ports: 1,  ip: '192.168.1.50'  },
  pc2:    { type: 'pc',     name: 'Media PC',     ports: 1,  ip: '192.168.1.51'  },
};

// When each device first appears on canvas (its "drop" moment).
const DEVICE_APPEAR = {
  router: 6.40,
  switch: 9.95,
  server: 10.55,
  pc1:    11.15,
  pc2:    11.75,
};

// Port hit-points on the canvas, stage-absolute.
const CANVAS_TARGETS = {
  'router-bottom':       { x: 960,  y: 315 },
  'switch-top':          { x: 960,  y: 444 },
  // Three distinct downlink ports — match cable fromOffsets exactly.
  'switch-port-left':    { x: 900,  y: 565 },   // c2 → server
  'switch-port-center':  { x: 960,  y: 565 },   // c3 → pc1
  'switch-port-right':   { x: 1020, y: 565 },   // c4 → pc2
  'switch-bottom':       { x: 960,  y: 565 },   // generic fallback
  'server-top':          { x: 620,  y: 734 },
  'pc1-top':             { x: 920,  y: 734 },
  'pc2-top':             { x: 1220, y: 734 },
  // Drop targets
  'drop-router':         { x: 960,  y: 265 },
  'drop-switch':         { x: 960,  y: 505 },
  'drop-server':         { x: 620,  y: 775 },
  'drop-pc1':            { x: 920,  y: 775 },
  'drop-pc2':            { x: 1220, y: 775 },
  // Selecting the switch device
  'switch-center':       { x: 960,  y: 505 },
};

// Cables draw rhythmically: ~0.5s each, ~0.3s gap, 4 cables in ~2.9s.
const CABLES = [
  { id: 'c1', from: 'router', to: 'switch', drawStart: 14.00, drawEnd: 14.55 },
  { id: 'c2', from: 'switch', to: 'server', drawStart: 14.85, drawEnd: 15.40, fromOffset: -60 },
  { id: 'c3', from: 'switch', to: 'pc1',    drawStart: 15.65, drawEnd: 16.20, fromOffset:   0 },
  { id: 'c4', from: 'switch', to: 'pc2',    drawStart: 16.45, drawEnd: 17.00, fromOffset: +60 },
];

// ── Math helpers ─────────────────────────────────────────────────────────────
const lerp = (a, b, t) => a + (b - a) * t;
const inRange = (t, a, b) => t >= a && t <= b;
const betw = (t, a, b) => {
  if (t <= a) return 0;
  if (t >= b) return 1;
  return (t - a) / (b - a);
};
const easeOut = (t) => 1 - Math.pow(1 - t, 3);
const easeInOut = (t) => t < 0.5 ? 4*t*t*t : 1 - Math.pow(-2*t + 2, 3) / 2;

// Resolve a keyframe to a {x,y} position. Accepts either explicit x/y, or a
// `target` name that's looked up in the targets dictionary (DOM or canvas
// constants). Returns null when a named target hasn't been resolved yet so
// the caller can substitute a safe fallback.
function resolveKf(kf, targets) {
  if (kf.target) {
    const t = targets[kf.target];
    if (!t) return null;
    return { x: t.x + (kf.dx || 0), y: t.y + (kf.dy || 0) };
  }
  if (typeof kf.x !== 'number' || typeof kf.y !== 'number') return null;
  return { x: kf.x, y: kf.y };
}

const SAFE_FALLBACK = { x: W / 2, y: H / 2 };

// Cursor keyframe interpolator (with name resolution + safe NaN guard).
function interpKeyframes(kfs, time, targets) {
  if (time <= kfs[0].t) return resolveKf(kfs[0], targets) || SAFE_FALLBACK;
  for (let i = 0; i < kfs.length - 1; i++) {
    const a = kfs[i], b = kfs[i + 1];
    if (time >= a.t && time <= b.t) {
      const local = (time - a.t) / (b.t - a.t || 1);
      const e = (b.ease || easeInOut)(local);
      const A = resolveKf(a, targets) || SAFE_FALLBACK;
      const B = resolveKf(b, targets) || SAFE_FALLBACK;
      return { x: lerp(A.x, B.x, e), y: lerp(A.y, B.y, e) };
    }
  }
  return resolveKf(kfs[kfs.length - 1], targets) || SAFE_FALLBACK;
}

function clickAt(events, time) {
  for (const e of events) if (time >= e.t && time <= e.t + e.dur) return true;
  return false;
}
function rippleSize(events, time) {
  for (const e of events) {
    const dt = time - e.t;
    if (dt >= 0 && dt < 0.55) return 8 + dt * 70;
  }
  return null;
}

Object.assign(window, {
  Times, TOTAL, W, H,
  DEVICE_LAYOUT, DEVICE_INFO, DEVICE_APPEAR,
  CANVAS_TARGETS, CABLES,
  lerp, inRange, betw, easeOut, easeInOut,
  interpKeyframes, clickAt, rippleSize, resolveKf,
});
