import * as getters from '~/diffs/store/getters';
import state from '~/diffs/store/modules/diff_state';
import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants';
import discussion from '../mock_data/diff_discussions';

describe('Diffs Module Getters', () => {
  let localState;
  let discussionMock;
  let discussionMock1;

  const diffFileMock = {
    fileHash: '9732849daca6ae818696d9575f5d1207d1a7f8bb',
  };

  beforeEach(() => {
    localState = state();
    discussionMock = { ...discussion };
    discussionMock.diff_file.file_hash = diffFileMock.fileHash;

    discussionMock1 = { ...discussion };
    discussionMock1.diff_file.file_hash = diffFileMock.fileHash;
  });

  describe('isParallelView', () => {
    it('should return true if view set to parallel view', () => {
      localState.diffViewType = PARALLEL_DIFF_VIEW_TYPE;

      expect(getters.isParallelView(localState)).toEqual(true);
    });

    it('should return false if view not to parallel view', () => {
      localState.diffViewType = INLINE_DIFF_VIEW_TYPE;

      expect(getters.isParallelView(localState)).toEqual(false);
    });
  });

  describe('isInlineView', () => {
    it('should return true if view set to inline view', () => {
      localState.diffViewType = INLINE_DIFF_VIEW_TYPE;

      expect(getters.isInlineView(localState)).toEqual(true);
    });

    it('should return false if view not to inline view', () => {
      localState.diffViewType = PARALLEL_DIFF_VIEW_TYPE;

      expect(getters.isInlineView(localState)).toEqual(false);
    });
  });

  describe('whichCollapsedTypes', () => {
    const autoCollapsedFile = { viewer: { automaticallyCollapsed: true, manuallyCollapsed: null } };
    const manuallyCollapsedFile = {
      viewer: { automaticallyCollapsed: false, manuallyCollapsed: true },
    };
    const openFile = { viewer: { automaticallyCollapsed: false, manuallyCollapsed: false } };

    it.each`
      description                                 | value    | files
      ${'all files are automatically collapsed'}  | ${true}  | ${[{ ...autoCollapsedFile }, { ...autoCollapsedFile }]}
      ${'all files are manually collapsed'}       | ${true}  | ${[{ ...manuallyCollapsedFile }, { ...manuallyCollapsedFile }]}
      ${'no files are collapsed in any way'}      | ${false} | ${[{ ...openFile }, { ...openFile }]}
      ${'some files are collapsed in either way'} | ${true}  | ${[{ ...manuallyCollapsedFile }, { ...autoCollapsedFile }, { ...openFile }]}
    `('`any` is $value when $description', ({ value, files }) => {
      localState.diffFiles = files;

      const getterResult = getters.whichCollapsedTypes(localState);

      expect(getterResult.any).toEqual(value);
    });

    it.each`
      description                                 | value    | files
      ${'all files are automatically collapsed'}  | ${true}  | ${[{ ...autoCollapsedFile }, { ...autoCollapsedFile }]}
      ${'all files are manually collapsed'}       | ${false} | ${[{ ...manuallyCollapsedFile }, { ...manuallyCollapsedFile }]}
      ${'no files are collapsed in any way'}      | ${false} | ${[{ ...openFile }, { ...openFile }]}
      ${'some files are collapsed in either way'} | ${true}  | ${[{ ...manuallyCollapsedFile }, { ...autoCollapsedFile }, { ...openFile }]}
    `('`automatic` is $value when $description', ({ value, files }) => {
      localState.diffFiles = files;

      const getterResult = getters.whichCollapsedTypes(localState);

      expect(getterResult.automatic).toEqual(value);
    });

    it.each`
      description                                 | value    | files
      ${'all files are automatically collapsed'}  | ${false} | ${[{ ...autoCollapsedFile }, { ...autoCollapsedFile }]}
      ${'all files are manually collapsed'}       | ${true}  | ${[{ ...manuallyCollapsedFile }, { ...manuallyCollapsedFile }]}
      ${'no files are collapsed in any way'}      | ${false} | ${[{ ...openFile }, { ...openFile }]}
      ${'some files are collapsed in either way'} | ${true}  | ${[{ ...manuallyCollapsedFile }, { ...autoCollapsedFile }, { ...openFile }]}
    `('`manual` is $value when $description', ({ value, files }) => {
      localState.diffFiles = files;

      const getterResult = getters.whichCollapsedTypes(localState);

      expect(getterResult.manual).toEqual(value);
    });
  });

  describe('commitId', () => {
    it('returns commit id when is set', () => {
      const commitID = '800f7a91';
      localState.commit = {
        id: commitID,
      };

      expect(getters.commitId(localState)).toEqual(commitID);
    });

    it('returns null when no commit is set', () => {
      expect(getters.commitId(localState)).toEqual(null);
    });
  });

  describe('diffHasAllExpandedDiscussions', () => {
    it('returns true when all discussions are expanded', () => {
      expect(
        getters.diffHasAllExpandedDiscussions(localState, {
          getDiffFileDiscussions: () => [discussionMock, discussionMock],
        })(diffFileMock),
      ).toEqual(true);
    });

    it('returns false when there are no discussions', () => {
      expect(
        getters.diffHasAllExpandedDiscussions(localState, {
          getDiffFileDiscussions: () => [],
        })(diffFileMock),
      ).toEqual(false);
    });

    it('returns false when one discussions is collapsed', () => {
      discussionMock1.expanded = false;

      expect(
        getters.diffHasAllExpandedDiscussions(localState, {
          getDiffFileDiscussions: () => [discussionMock, discussionMock1],
        })(diffFileMock),
      ).toEqual(false);
    });
  });

  describe('diffHasAllCollapsedDiscussions', () => {
    it('returns true when all discussions are collapsed', () => {
      discussionMock.diff_file.file_hash = diffFileMock.fileHash;
      discussionMock.expanded = false;

      expect(
        getters.diffHasAllCollapsedDiscussions(localState, {
          getDiffFileDiscussions: () => [discussionMock],
        })(diffFileMock),
      ).toEqual(true);
    });

    it('returns false when there are no discussions', () => {
      expect(
        getters.diffHasAllCollapsedDiscussions(localState, {
          getDiffFileDiscussions: () => [],
        })(diffFileMock),
      ).toEqual(false);
    });

    it('returns false when one discussions is expanded', () => {
      discussionMock1.expanded = false;

      expect(
        getters.diffHasAllCollapsedDiscussions(localState, {
          getDiffFileDiscussions: () => [discussionMock, discussionMock1],
        })(diffFileMock),
      ).toEqual(false);
    });
  });

  describe('diffHasExpandedDiscussions', () => {
    it('returns true when one of the discussions is expanded', () => {
      const diffFile = {
        parallel_diff_lines: [],
        highlighted_diff_lines: [
          {
            discussions: [discussionMock, discussionMock],
            discussionsExpanded: true,
          },
        ],
      };

      expect(getters.diffHasExpandedDiscussions(localState)(diffFile)).toEqual(true);
    });

    it('returns false when there are no discussions', () => {
      const diffFile = {
        parallel_diff_lines: [],
        highlighted_diff_lines: [
          {
            discussions: [],
            discussionsExpanded: true,
          },
        ],
      };
      expect(getters.diffHasExpandedDiscussions(localState)(diffFile)).toEqual(false);
    });

    it('returns false when no discussion is expanded', () => {
      const diffFile = {
        parallel_diff_lines: [],
        highlighted_diff_lines: [
          {
            discussions: [discussionMock, discussionMock],
            discussionsExpanded: false,
          },
        ],
      };

      expect(getters.diffHasExpandedDiscussions(localState)(diffFile)).toEqual(false);
    });
  });

  describe('diffHasDiscussions', () => {
    it('returns true when getDiffFileDiscussions returns discussions', () => {
      const diffFile = {
        parallel_diff_lines: [],
        highlighted_diff_lines: [
          {
            discussions: [discussionMock, discussionMock],
            discussionsExpanded: false,
          },
        ],
      };

      expect(getters.diffHasDiscussions(localState)(diffFile)).toEqual(true);
    });

    it('returns false when getDiffFileDiscussions returns no discussions', () => {
      const diffFile = {
        parallel_diff_lines: [],
        highlighted_diff_lines: [
          {
            discussions: [],
            discussionsExpanded: false,
          },
        ],
      };

      expect(getters.diffHasDiscussions(localState)(diffFile)).toEqual(false);
    });
  });

  describe('getDiffFileDiscussions', () => {
    it('returns an array with discussions when fileHash matches and the discussion belongs to a diff', () => {
      discussionMock.diff_file.file_hash = diffFileMock.file_hash;

      expect(
        getters.getDiffFileDiscussions(
          localState,
          {},
          {},
          { discussions: [discussionMock] },
        )(diffFileMock).length,
      ).toEqual(1);
    });

    it('returns an empty array when no discussions are found in the given diff', () => {
      expect(
        getters.getDiffFileDiscussions(localState, {}, {}, { discussions: [] })(diffFileMock)
          .length,
      ).toEqual(0);
    });
  });

  describe('getDiffFileByHash', () => {
    it('returns file by hash', () => {
      const fileA = {
        file_hash: '123',
      };
      const fileB = {
        file_hash: '456',
      };
      localState.diffFiles = [fileA, fileB];

      expect(getters.getDiffFileByHash(localState)('456')).toEqual(fileB);
    });

    it('returns null if no matching file is found', () => {
      localState.diffFiles = [];

      expect(getters.getDiffFileByHash(localState)('123')).toBeUndefined();
    });
  });

  describe('allBlobs', () => {
    it('returns an array of blobs', () => {
      localState.treeEntries = {
        file: {
          type: 'blob',
          path: 'file',
          parentPath: '/',
          tree: [],
        },
        tree: {
          type: 'tree',
          path: 'tree',
          parentPath: '/',
          tree: [],
        },
      };

      expect(
        getters.allBlobs(localState, {
          flatBlobsList: getters.flatBlobsList(localState),
        }),
      ).toEqual([
        {
          isHeader: true,
          path: '/',
          tree: [
            {
              parentPath: '/',
              path: 'file',
              tree: [],
              type: 'blob',
            },
          ],
        },
      ]);
    });
  });

  describe('currentDiffIndex', () => {
    it('returns index of currently selected diff in diffList', () => {
      localState.diffFiles = [{ file_hash: '111' }, { file_hash: '222' }, { file_hash: '333' }];
      localState.currentDiffFileId = '222';

      expect(getters.currentDiffIndex(localState)).toEqual(1);

      localState.currentDiffFileId = '333';

      expect(getters.currentDiffIndex(localState)).toEqual(2);
    });

    it('returns 0 if no diff is selected yet or diff is not found', () => {
      localState.diffFiles = [{ file_hash: '111' }, { file_hash: '222' }, { file_hash: '333' }];
      localState.currentDiffFileId = '';

      expect(getters.currentDiffIndex(localState)).toEqual(0);
    });
  });

  describe('fileLineCoverage', () => {
    beforeEach(() => {
      Object.assign(localState.coverageFiles, { files: { 'app.js': { 1: 0, 2: 5 } } });
    });

    it('returns empty object when no coverage data is available', () => {
      Object.assign(localState.coverageFiles, {});

      expect(getters.fileLineCoverage(localState)('test.js', 2)).toEqual({});
    });

    it('returns empty object when unknown filename is passed', () => {
      expect(getters.fileLineCoverage(localState)('test.js', 2)).toEqual({});
    });

    it('returns no-coverage info when correct filename and line is passed', () => {
      expect(getters.fileLineCoverage(localState)('app.js', 1)).toEqual({
        text: 'No test coverage',
        class: 'no-coverage',
      });
    });

    it('returns coverage info when correct filename and line is passed', () => {
      expect(getters.fileLineCoverage(localState)('app.js', 2)).toEqual({
        text: 'Test coverage: 5 hits',
        class: 'coverage',
      });
    });
  });

  describe('fileReviews', () => {
    const file1 = { id: '123', file_identifier_hash: 'abc' };
    const file2 = { id: '098', file_identifier_hash: 'abc' };

    it.each`
      reviews                           | files             | fileReviews
      ${{}}                             | ${[file1, file2]} | ${[false, false]}
      ${{ abc: ['123'] }}               | ${[file1, file2]} | ${[true, false]}
      ${{ abc: ['098'] }}               | ${[file1, file2]} | ${[false, true]}
      ${{ def: ['123'] }}               | ${[file1, file2]} | ${[false, false]}
      ${{ abc: ['123'], def: ['098'] }} | ${[]}             | ${[]}
    `(
      'returns $fileReviews based on the diff files in state and the existing reviews $reviews',
      ({ reviews, files, fileReviews }) => {
        localState.diffFiles = files;
        localState.mrReviews = reviews;

        expect(getters.fileReviews(localState)).toStrictEqual(fileReviews);
      },
    );
  });
});
