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

import { createServer } from "vite";

let server;
let admission;
let rerunPresentationStatus;
let recordedMediaPresentationState;

before(async () => {
  server = await createServer({
    appType: "custom",
    logLevel: "silent",
    server: { middlewareMode: true },
  });
  admission = await server.ssrLoadModule(
    "/src/core/observation/recordedSessionAdmission.ts",
  );
  ({ rerunPresentationStatus } = await server.ssrLoadModule(
    "/src/components/RerunViewport.tsx",
  ));
  ({ recordedMediaPresentationState } = await server.ssrLoadModule(
    "/src/components/RecordedFmp4Player.tsx",
  ));
});

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

function camera(phase, byteLength = 1_024) {
  return { phase, byteLength, message: null };
}

test("recorded session admits RRD and every declared camera as one atomic generation", () => {
  const ids = ["camera.left", "camera.right"];
  const oneCamera = {
    "camera.left": camera("ready"),
    "camera.right": camera("pending"),
  };
  const partialGate = admission.recordedSessionAdmissionPhase("ready", ids, oneCamera);
  assert.equal(partialGate, "loading");
  assert.equal(rerunPresentationStatus("ready", partialGate, true), "loading");
  assert.equal(
    recordedMediaPresentationState("ready", "generation", "generation", false, partialGate),
    "loading",
  );

  const completeGate = admission.recordedSessionAdmissionPhase("ready", ids, {
    ...oneCamera,
    "camera.right": camera("ready"),
  });
  assert.equal(completeGate, "ready");
  assert.equal(rerunPresentationStatus("ready", completeGate, true), "ready");
  assert.equal(
    recordedMediaPresentationState("ready", "generation", "generation", false, completeGate),
    "ready",
  );
});

test("any RRD or camera failure closes the complete recorded session", () => {
  const ids = ["camera.left", "camera.right"];
  const cameras = {
    "camera.left": camera("ready"),
    "camera.right": camera("error"),
  };
  assert.equal(admission.recordedSessionAdmissionPhase("ready", ids, cameras), "error");
  assert.equal(admission.recordedSessionAdmissionPhase("error", ids, {
    ...cameras,
    "camera.right": camera("ready"),
  }), "error");
  assert.equal(rerunPresentationStatus("ready", "error", true), "error");
  assert.equal(
    recordedMediaPresentationState("ready", "generation", "generation", false, "error"),
    "error",
  );
});

test("camera admission keeps source scheduling bounded but has no duration or byte ceiling", () => {
  const {
    MAX_RECORDED_CAMERA_SOURCES,
    recordedCameraDescriptorPreflight,
  } = admission;
  assert.equal(MAX_RECORDED_CAMERA_SOURCES, 16);
  assert.equal(recordedCameraDescriptorPreflight(
    Array.from({ length: 2 }, (_, index) => ({
      id: `camera.${index}`,
      byteLength: 36_000_000_000,
    })),
  ), "ready");
  assert.equal(recordedCameraDescriptorPreflight(
    Array.from({ length: 17 }, (_, index) => ({ id: `camera.${index}`, byteLength: 1 })),
  ), "error");
  assert.equal(recordedCameraDescriptorPreflight([
    { id: "camera.ten-hours", byteLength: 36_000_000_000 },
  ]), "ready");
  assert.equal(recordedCameraDescriptorPreflight([
    { id: "camera.invalid", byteLength: Number.MAX_SAFE_INTEGER + 1 },
  ]), "error");
  assert.equal(recordedCameraDescriptorPreflight([
    { id: "camera.duplicate", byteLength: 1 },
    { id: "camera.duplicate", byteLength: 1 },
  ]), "error");
});

test("camera preparation remains single-flight and retains the loading permit", () => {
  const ids = ["camera.first", "camera.preferred"];
  const cameras = {
    "camera.first": camera("loading"),
    "camera.preferred": camera("pending"),
  };
  assert.deepEqual(
    admission.nextRecordedCameraPreparationIds(
      ids,
      cameras,
      new Set(["camera.preferred"]),
    ),
    ["camera.first"],
  );
  assert.deepEqual(
    admission.nextRecordedCameraPreparationIds(ids, {
      ...cameras,
      "camera.first": camera("ready"),
    }),
    ["camera.preferred"],
  );
});

test("new render workers close readiness and stale callbacks cannot reopen it", () => {
  const ready = { ...camera("ready"), workerGeneration: 1 };
  const remounted = admission.mergeRecordedCameraAdmission(ready, {
    ...camera("loading"),
    workerGeneration: 2,
  });
  assert.equal(remounted.phase, "loading");
  assert.equal(remounted.workerGeneration, 2);
  assert.equal(admission.mergeRecordedCameraAdmission(remounted, {
    ...camera("ready"),
    workerGeneration: 1,
  }), remounted);
  const admitted = admission.mergeRecordedCameraAdmission(remounted, {
    ...camera("ready"),
    workerGeneration: 2,
  });
  assert.equal(admitted.phase, "ready");
  const failed = admission.mergeRecordedCameraAdmission(admitted, {
    ...camera("error"),
    workerGeneration: 2,
  });
  assert.equal(failed.phase, "error");
  assert.equal(admission.mergeRecordedCameraAdmission(failed, {
    ...camera("loading"),
    workerGeneration: 3,
  }), failed);
});

test("recorded player is not mounted for a camera without a scheduler permit", async () => {
  const source = await readFile(
    new URL("../src/components/ObservationSources.tsx", import.meta.url),
    "utf8",
  );
  const placeholder = source.indexOf("if (!prepareRecorded)");
  const player = source.indexOf("<RecordedFmp4Player", placeholder);
  assert.ok(placeholder >= 0 && player > placeholder);
  assert.match(source.slice(placeholder, player), /return\s*\(/);
});
