/**
 * @license
 * Copyright 2016 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import '../test/common-test-setup-karma';
import {
  createChange,
  createChangeMessageInfo,
  createRevision,
} from '../test/test-data-generators';
import {
  BasePatchSetNum,
  ChangeInfo,
  EditPatchSetNum,
  PatchSetNum,
  ReviewInputTag,
} from '../types/common';
import {
  _testOnly_computeWipForPatchSets,
  computeAllPatchSets,
  findEditParentPatchNum,
  findEditParentRevision,
  getParentIndex,
  getRevisionByPatchNum,
  isMergeParent,
  sortRevisions,
} from './patch-set-util';

suite('gr-patch-set-util tests', () => {
  test('getRevisionByPatchNum', () => {
    const revisions = [createRevision(0), createRevision(1), createRevision(2)];
    assert.deepEqual(
      getRevisionByPatchNum(revisions, 1 as PatchSetNum),
      revisions[1]
    );
    assert.deepEqual(
      getRevisionByPatchNum(revisions, 2 as PatchSetNum),
      revisions[2]
    );
    assert.equal(getRevisionByPatchNum(revisions, 3 as PatchSetNum), undefined);
  });

  test('_computeWipForPatchSets', () => {
    // Compute patch sets for a given timeline on a change. The initial WIP
    // property of the change can be true or false. The map of tags by
    // revision is keyed by patch set number. Each value is a list of change
    // message tags in the order that they occurred in the timeline. These
    // indicate actions that modify the WIP property of the change and/or
    // create new patch sets.
    //
    // Returns the actual results with an assertWip method that can be used
    // to compare against an expected value for a particular patch set.
    const compute = (
      initialWip: boolean,
      tagsByRevision: Map<
        number | 'edit' | 'PARENT',
        (ReviewInputTag | undefined)[]
      >
    ) => {
      const change: ChangeInfo = {
        ...createChange(),
        messages: [],
        work_in_progress: initialWip,
      };
      for (const rev of tagsByRevision.keys()) {
        for (const tag of tagsByRevision.get(rev)!) {
          change.messages!.push({
            ...createChangeMessageInfo(),
            tag,
            _revision_number: rev as PatchSetNum,
          });
        }
      }
      const patchSets = Array.from(tagsByRevision.keys()).map(rev => {
        return {num: rev as PatchSetNum, desc: 'test', sha: `rev${rev}`};
      });
      const patchNums = _testOnly_computeWipForPatchSets(change, patchSets);
      const verifier = {
        assertWip(revision: number, expectedWip: boolean) {
          const patchNum = patchNums.find(
            patchNum => patchNum.num === (revision as PatchSetNum)
          );
          if (!patchNum) {
            assert.fail(`revision ${revision} not found`);
          }
          assert.equal(
            patchNum.wip,
            expectedWip,
            `wip state for ${revision} ` +
              `is ${patchNum.wip}; expected ${expectedWip}`
          );
          return verifier;
        },
      };
      return verifier;
    };

    const upload = 'upload' as ReviewInputTag;

    compute(false, new Map([[1, [upload]]])).assertWip(1, false);
    compute(true, new Map([[1, [upload]]])).assertWip(1, true);

    const setWip = 'autogenerated:gerrit:setWorkInProgress' as ReviewInputTag;
    const uploadInWip = 'autogenerated:gerrit:newWipPatchSet' as ReviewInputTag;
    const clearWip = 'autogenerated:gerrit:setReadyForReview' as ReviewInputTag;

    compute(
      false,
      new Map([
        [1, [upload, setWip]],
        [2, [upload]],
        [3, [upload, clearWip]],
        [4, [upload, setWip]],
      ])
    )
      .assertWip(1, false) // Change was created with PS1 ready for review
      .assertWip(2, true) // PS2 was uploaded during WIP
      .assertWip(3, false) // PS3 was marked ready for review after upload
      .assertWip(4, false); // PS4 was uploaded ready for review

    compute(
      false,
      new Map([
        [1, [uploadInWip, undefined, 'addReviewer' as ReviewInputTag]],
        [2, [upload]],
        [3, [upload, clearWip, setWip]],
        [4, [upload]],
        [5, [upload, clearWip]],
        [6, [uploadInWip]],
      ])
    )
      .assertWip(1, true) // Change was created in WIP
      .assertWip(2, true) // PS2 was uploaded during WIP
      .assertWip(3, false) // PS3 was marked ready for review
      .assertWip(4, true) // PS4 was uploaded during WIP
      .assertWip(5, false) // PS5 was marked ready for review
      .assertWip(6, true); // PS6 was uploaded with WIP option
  });

  test('isMergeParent', () => {
    assert.isFalse(isMergeParent(1 as PatchSetNum));
    assert.isFalse(isMergeParent(4321 as PatchSetNum));
    assert.isFalse(isMergeParent('edit' as PatchSetNum));
    assert.isFalse(isMergeParent('PARENT' as PatchSetNum));
    assert.isFalse(isMergeParent(0 as PatchSetNum));

    assert.isTrue(isMergeParent(-23 as PatchSetNum));
    assert.isTrue(isMergeParent(-1 as PatchSetNum));
  });

  test('findEditParentRevision', () => {
    const revisions = [createRevision(0), createRevision(1), createRevision(2)];
    assert.strictEqual(findEditParentRevision(revisions), null);

    revisions.push({
      ...createRevision(),
      _number: EditPatchSetNum,
      basePatchNum: 3 as BasePatchSetNum,
    });
    assert.strictEqual(findEditParentRevision(revisions), null);

    revisions.push(createRevision(3));
    assert.deepEqual(findEditParentRevision(revisions), createRevision(3));
  });

  test('findEditParentPatchNum', () => {
    const revisions = [createRevision(0), createRevision(1), createRevision(2)];
    assert.equal(findEditParentPatchNum(revisions), -1);

    revisions.push(
      {
        ...createRevision(),
        _number: EditPatchSetNum,
        basePatchNum: 3 as BasePatchSetNum,
      },
      createRevision(3)
    );
    assert.deepEqual(findEditParentPatchNum(revisions), 3);
  });

  test('sortRevisions', () => {
    const revisions = [createRevision(0), createRevision(2), createRevision(1)];
    const sorted = [createRevision(2), createRevision(1), createRevision(0)];

    assert.deepEqual(sortRevisions(revisions), sorted);

    // Edit patchset should follow directly after its basePatchNum.
    revisions.push({
      ...createRevision(),
      _number: EditPatchSetNum,
      basePatchNum: 2 as BasePatchSetNum,
    });
    sorted.unshift({
      ...createRevision(),
      _number: EditPatchSetNum,
      basePatchNum: 2 as BasePatchSetNum,
    });
    assert.deepEqual(sortRevisions(revisions), sorted);

    revisions[0].basePatchNum = 0 as BasePatchSetNum;
    const edit = sorted.shift()!;
    edit.basePatchNum = 0 as BasePatchSetNum;
    // Edit patchset should be at index 2.
    sorted.splice(2, 0, edit);
    assert.deepEqual(sortRevisions(revisions), sorted);
  });

  test('getParentIndex', () => {
    assert.equal(getParentIndex(-4 as PatchSetNum), 4);
  });

  test('computeAllPatchSets', () => {
    const expected = [
      {num: 4 as PatchSetNum, desc: 'test', sha: 'rev4'},
      {num: 3 as PatchSetNum, desc: 'test', sha: 'rev3'},
      {num: 2 as PatchSetNum, desc: 'test', sha: 'rev2'},
      {num: 1 as PatchSetNum, desc: 'test', sha: 'rev1'},
    ];
    const patchNums = computeAllPatchSets({
      ...createChange(),
      revisions: {
        rev1: {...createRevision(1), description: 'test'},
        rev2: {...createRevision(2), description: 'test'},
        rev3: {...createRevision(3), description: 'test'},
        rev4: {...createRevision(4), description: 'test'},
      },
    });
    assert.equal(patchNums.length, expected.length);
    for (let i = 0; i < expected.length; i++) {
      assert.deepEqual(patchNums[i], expected[i]);
    }
  });
});
