import assert from "node:assert/strict";
import { after, before, test } from "node:test";

import { createServer } from "vite";

let server;
let canPublishRecordedPlaybackController;
let createRecordedAutoplayGate;
let isRecordedPlaybackReady;
let isRecordedPlaybackPresentationReady;
let isUsableRecordedPlaybackRange;
let recordedPlaybackBufferState;
let recordedPlaybackRangeWhenReady;

before(async () => {
  server = await createServer({
    appType: "custom",
    logLevel: "silent",
    server: { middlewareMode: true },
  });
  ({
    canPublishRecordedPlaybackController,
    createRecordedAutoplayGate,
    isRecordedPlaybackReady,
    isRecordedPlaybackPresentationReady,
    isUsableRecordedPlaybackRange,
    recordedPlaybackBufferState,
    recordedPlaybackRangeWhenReady,
  } = await server.ssrLoadModule("/src/components/RerunViewport.tsx"));
});

after(async () => {
  await server?.close();
});

test("a first frame reports buffer telemetry but is not ready for presentation", () => {
  assert.equal(isUsableRecordedPlaybackRange(null), false);
  assert.equal(isUsableRecordedPlaybackRange({ min: Number.NaN, max: 0 }), false);
  assert.equal(isUsableRecordedPlaybackRange({ min: 2, max: 1 }), false);
  assert.equal(isUsableRecordedPlaybackRange({ min: 0, max: 0 }), true);

  const firstFrame = recordedPlaybackBufferState({ min: 0, max: 0 }, 20);
  assert.deepEqual(firstFrame, {
    bufferedEndNs: 0,
    expectedStartNs: 0,
    expectedEndNs: 20_000_000_000,
    bufferProgress: 0,
    fullyBuffered: false,
  });
  assert.equal(isRecordedPlaybackReady(true, true, firstFrame), false);
  assert.equal(recordedPlaybackRangeWhenReady({ min: 0, max: 0 }, firstFrame, true), null);
});

test("host timeline remains unmounted until the verified recording is fully ready", () => {
  const partial = {
    recordingId: "partial",
    timeline: "session_time",
    rangeNs: null,
    currentNs: 0,
    playing: false,
    bufferedEndNs: 5,
    expectedStartNs: 0,
    expectedEndNs: 10,
    bufferProgress: 0.5,
    fullyBuffered: false,
  };
  assert.equal(isRecordedPlaybackPresentationReady("loading", partial), false);
  assert.equal(isRecordedPlaybackPresentationReady("ready", partial), false);
  assert.equal(isRecordedPlaybackPresentationReady("error", partial), false);
  assert.equal(isRecordedPlaybackPresentationReady("ready", {
    ...partial,
    rangeNs: { min: 0, max: 10 },
    bufferedEndNs: 10,
    bufferProgress: 1,
    fullyBuffered: true,
  }), true);
});

test("buffer progress grows independently and preserves the full-buffer tolerance", () => {
  assert.deepEqual(recordedPlaybackBufferState({ min: 0, max: 5_000_000_000 }, 20), {
    bufferedEndNs: 5_000_000_000,
    expectedStartNs: 0,
    expectedEndNs: 20_000_000_000,
    bufferProgress: 0.25,
    fullyBuffered: false,
  });

  const complete = recordedPlaybackBufferState({ min: 0, max: 19_999_500_000 }, 20);
  assert.equal(complete.bufferProgress, 0.999975);
  assert.equal(complete.fullyBuffered, true);
  assert.equal(isRecordedPlaybackReady(false, true, complete), false);
  assert.equal(isRecordedPlaybackReady(true, false, complete), false);
  assert.equal(isRecordedPlaybackReady(true, true, complete), true);
  assert.equal(
    recordedPlaybackRangeWhenReady({ min: 0, max: 19_999_500_000 }, complete, false),
    null,
  );
  assert.deepEqual(
    recordedPlaybackRangeWhenReady({ min: 0, max: 19_999_500_000 }, complete, true),
    { min: 0, max: 19_999_500_000 },
  );

  const missingDeclaredStart = recordedPlaybackBufferState(
    { min: 5_000_000_000, max: 20_000_000_000 },
    20,
    0,
  );
  assert.equal(missingDeclaredStart.bufferProgress, 1);
  assert.equal(missingDeclaredStart.fullyBuffered, false);
  assert.equal(isRecordedPlaybackReady(true, true, missingDeclaredStart), false);
});

test("a verified split boundary spill covers and clamps the declared LAB window", () => {
  const actualRange = {
    min: 34_756_228_209,
    max: 95_383_857_292,
  };
  const buffer = recordedPlaybackBufferState(
    actualRange,
    95.383857292,
    35.421857292,
  );

  assert.equal(buffer.bufferProgress, 1);
  assert.equal(buffer.fullyBuffered, true);
  assert.equal(isRecordedPlaybackReady(true, true, buffer), true);
  assert.deepEqual(
    recordedPlaybackRangeWhenReady(actualRange, buffer, true),
    {
      min: 35_421_857_292,
      max: 95_383_857_292,
    },
  );
});

test("recorded autoplay waits for the full range and then runs exactly once", () => {
  const gate = createRecordedAutoplayGate();
  const seeks = [];
  let plays = 0;
  const seek = (value) => seeks.push(value);
  const play = () => {
    plays += 1;
  };

  assert.equal(gate.attempt(false, true, true, { min: 0, max: 0 }, seek, play), false);
  assert.equal(gate.attempt(true, false, true, { min: 0, max: 500_000_000 }, seek, play), false);
  assert.equal(gate.attempt(true, true, false, { min: 0, max: 20_000_000_000 }, seek, play), false);
  assert.deepEqual(seeks, []);
  assert.equal(plays, 0);
  assert.equal(gate.attempt(true, true, true, { min: 0, max: 20_000_000_000 }, seek, play), true);
  assert.equal(gate.attempt(true, true, true, { min: 0, max: 20_000_000_000 }, seek, play), false);
  assert.deepEqual(seeks, [0]);
  assert.equal(plays, 1);
  assert.equal(gate.attempted(), true);
});

test("recorded autoplay starts at the first presentable camera frame without shrinking the range", () => {
  const gate = createRecordedAutoplayGate();
  const seeks = [];
  const range = { min: 0, max: 535_717_620_042 };

  assert.equal(gate.attempt(
    true,
    true,
    true,
    range,
    (value) => seeks.push(value),
    () => {},
    35_421_857_292,
  ), true);
  assert.deepEqual(seeks, [35_421_857_292]);
  assert.deepEqual(range, { min: 0, max: 535_717_620_042 });
});

test("recorded autoplay clamps an invalid presentation start to the admitted archive", () => {
  const before = createRecordedAutoplayGate();
  const after = createRecordedAutoplayGate();
  const seeks = [];
  const range = { min: 5, max: 10 };

  assert.equal(before.attempt(
    true,
    true,
    true,
    range,
    (value) => seeks.push(value),
    () => {},
    -50,
  ), true);
  assert.equal(after.attempt(
    true,
    true,
    true,
    range,
    (value) => seeks.push(value),
    () => {},
    50,
  ), true);
  assert.deepEqual(seeks, [5, 10]);
});

test("a failed vendor autoplay attempt is consumed instead of rewinding later", () => {
  const gate = createRecordedAutoplayGate();
  let seeks = 0;
  let plays = 0;

  assert.equal(gate.attempt(
    true,
    true,
    true,
    { min: 0, max: 1 },
    () => {
      seeks += 1;
    },
    () => {
      plays += 1;
      throw new Error("receiver raced its first frame");
    },
  ), false);
  assert.equal(gate.attempt(
    true,
    true,
    true,
    { min: 0, max: 2 },
    () => {
      seeks += 1;
    },
    () => {
      plays += 1;
    },
  ), false);
  assert.equal(seeks, 1);
  assert.equal(plays, 1);
});

test("recorded playback controller stays unpublished until the aggregate gate is ready", () => {
  assert.equal(canPublishRecordedPlaybackController(false, "ready"), false);
  assert.equal(canPublishRecordedPlaybackController(true, "loading"), false);
  assert.equal(canPublishRecordedPlaybackController(true, "error"), false);
  assert.equal(canPublishRecordedPlaybackController(true, "ready"), true);
});
