import {describe, it, expect} from "vitest";
import {phase0} from "@lodestar/types";
import {assertPeerRelevance, IrrelevantPeerCode} from "../../../../../src/network/peers/utils/assertPeerRelevance.js";

describe("network / peers / utils / assertPeerRelevance", () => {
  const correctForkDigest = Buffer.alloc(4, 0);
  const differentForkDigest = Buffer.alloc(4, 1);
  const ZERO_HASH = Buffer.alloc(32, 0);
  const differedRoot = Buffer.alloc(32, 1);

  const testCases: {
    id: string;
    remote: phase0.Status;
    currentSlot?: number;
    irrelevantType: ReturnType<typeof assertPeerRelevance>;
  }[] = [
    {
      id: "Reject incompatible forks",
      remote: {
        forkDigest: differentForkDigest,
        finalizedRoot: ZERO_HASH,
        finalizedEpoch: 0,
        headRoot: ZERO_HASH,
        headSlot: 0,
      },
      irrelevantType: {
        code: IrrelevantPeerCode.INCOMPATIBLE_FORKS,
        ours: correctForkDigest,
        theirs: differentForkDigest,
      },
    },
    {
      id: "Head is too far away from our clock",
      remote: {
        forkDigest: correctForkDigest,
        finalizedRoot: differedRoot,
        finalizedEpoch: 0,
        headRoot: ZERO_HASH,
        headSlot: 100, // Too far from current slot (= 0)
      },
      irrelevantType: {code: IrrelevantPeerCode.DIFFERENT_CLOCKS, slotDiff: 100},
    },
    {
      id: "Accept a finalized epoch equal to ours, with same root",
      remote: {
        forkDigest: correctForkDigest,
        finalizedRoot: ZERO_HASH,
        finalizedEpoch: 0,
        headRoot: ZERO_HASH,
        headSlot: 0,
      },
      irrelevantType: null,
    },
    {
      id: "Accept finalized epoch greater than ours",
      remote: {
        forkDigest: correctForkDigest,
        finalizedRoot: ZERO_HASH,
        finalizedEpoch: 100, // Greater than ours (= 0)
        headRoot: ZERO_HASH,
        headSlot: 0,
      },
      irrelevantType: null,
    },
    {
      id: "Accept during pre-genesis clock",
      remote: {
        forkDigest: correctForkDigest,
        finalizedRoot: ZERO_HASH,
        finalizedEpoch: 0,
        headRoot: ZERO_HASH,
        headSlot: 0,
      },
      // clock slot pre-genesis (< 0) by a good margin
      currentSlot: -50,
      irrelevantType: null,
    },
  ];

  for (const {id, remote, currentSlot, irrelevantType} of testCases) {
    it(id, async () => {
      const local = {
        forkDigest: correctForkDigest,
        finalizedRoot: ZERO_HASH,
        finalizedEpoch: 0,
        headRoot: ZERO_HASH,
        headSlot: 0,
      };

      expect(assertPeerRelevance(remote, local, currentSlot ?? 0)).toEqual(irrelevantType);
    });
  }
});
