import * as getters from '~/releases/stores/modules/detail/getters';

describe('Release detail getters', () => {
  describe('isExistingRelease', () => {
    it('returns true if the release is an existing release that already exists in the database', () => {
      const state = { tagName: 'test-tag-name' };

      expect(getters.isExistingRelease(state)).toBe(true);
    });

    it('returns false if the release is a new release that has not yet been saved to the database', () => {
      const state = { tagName: null };

      expect(getters.isExistingRelease(state)).toBe(false);
    });
  });

  describe('releaseLinksToCreate', () => {
    it("returns an empty array if state.release doesn't exist", () => {
      const state = {};
      expect(getters.releaseLinksToCreate(state)).toEqual([]);
    });

    it("returns all release links that aren't empty", () => {
      const emptyLinks = [
        { url: '', name: '' },
        { url: ' ', name: '' },
        { url: ' ', name: ' ' },
        { url: '\r\n', name: '\t' },
      ];

      const nonEmptyLinks = [
        { url: 'https://example.com/1', name: 'Example 1' },
        { url: '', name: 'Example 2' },
        { url: 'https://example.com/3', name: '' },
      ];

      const state = {
        release: {
          assets: {
            links: [...emptyLinks, ...nonEmptyLinks],
          },
        },
      };

      expect(getters.releaseLinksToCreate(state)).toEqual(nonEmptyLinks);
    });
  });

  describe('releaseLinksToDelete', () => {
    it("returns an empty array if state.originalRelease doesn't exist", () => {
      const state = {};
      expect(getters.releaseLinksToDelete(state)).toEqual([]);
    });

    it('returns all links associated with the original release', () => {
      const originalLinks = [
        { url: 'https://example.com/1', name: 'Example 1' },
        { url: 'https://example.com/2', name: 'Example 2' },
      ];

      const state = {
        originalRelease: {
          assets: {
            links: originalLinks,
          },
        },
      };

      expect(getters.releaseLinksToDelete(state)).toEqual(originalLinks);
    });
  });

  describe('validationErrors', () => {
    describe('when the form is valid', () => {
      it('returns no validation errors', () => {
        const state = {
          release: {
            tagName: 'test-tag-name',
            assets: {
              links: [
                { id: 1, url: 'https://example.com/valid', name: 'Link 1' },
                { id: 2, url: '', name: '' },
                { id: 3, url: '', name: ' ' },
                { id: 4, url: ' ', name: '' },
                { id: 5, url: ' ', name: ' ' },
              ],
            },
          },
        };

        const expectedErrors = {
          assets: {
            links: {
              1: {},
              2: {},
              3: {},
              4: {},
              5: {},
            },
          },
        };

        expect(getters.validationErrors(state)).toEqual(expectedErrors);
      });
    });

    describe('when the form is invalid', () => {
      let actualErrors;

      beforeEach(() => {
        const state = {
          release: {
            // empty tag name
            tagName: '',

            assets: {
              links: [
                // Duplicate URLs
                { id: 1, url: 'https://example.com/duplicate', name: 'Link 1' },
                { id: 2, url: 'https://example.com/duplicate', name: 'Link 2' },

                // the validation check ignores leading/trailing
                // whitespace and is case-insensitive
                { id: 3, url: '  \tHTTPS://EXAMPLE.COM/DUPLICATE\n\r\n  ', name: 'Link 3' },

                // Invalid URL format
                { id: 4, url: 'invalid', name: 'Link 4' },

                // Missing URL
                { id: 5, url: '', name: 'Link 5' },
                { id: 6, url: ' ', name: 'Link 6' },

                // Missing title
                { id: 7, url: 'https://example.com/valid/1', name: '' },
                { id: 8, url: 'https://example.com/valid/2', name: '  ' },
              ],
            },
          },
        };

        actualErrors = getters.validationErrors(state);
      });

      it('returns a validation error if the tag name is empty', () => {
        const expectedErrors = {
          isTagNameEmpty: true,
        };

        expect(actualErrors).toMatchObject(expectedErrors);
      });

      it('returns a validation error if links share a URL', () => {
        const expectedErrors = {
          assets: {
            links: {
              1: { isDuplicate: true },
              2: { isDuplicate: true },
              3: { isDuplicate: true },
            },
          },
        };

        expect(actualErrors).toMatchObject(expectedErrors);
      });

      it('returns a validation error if the URL is in the wrong format', () => {
        const expectedErrors = {
          assets: {
            links: {
              4: { isBadFormat: true },
            },
          },
        };

        expect(actualErrors).toMatchObject(expectedErrors);
      });

      it('returns a validation error if the URL missing (and the title is populated)', () => {
        const expectedErrors = {
          assets: {
            links: {
              6: { isUrlEmpty: true },
              5: { isUrlEmpty: true },
            },
          },
        };

        expect(actualErrors).toMatchObject(expectedErrors);
      });

      it('returns a validation error if the title missing (and the URL is populated)', () => {
        const expectedErrors = {
          assets: {
            links: {
              7: { isNameEmpty: true },
              8: { isNameEmpty: true },
            },
          },
        };

        expect(actualErrors).toMatchObject(expectedErrors);
      });
    });
  });

  describe('isValid', () => {
    // the value of state is not actually used by this getter
    const state = {};

    describe('when the form is valid', () => {
      it('returns true', () => {
        const mockGetters = {
          validationErrors: {
            assets: {
              links: {
                1: {},
              },
            },
          },
        };

        expect(getters.isValid(state, mockGetters)).toBe(true);
      });
    });

    describe('when an asset link contains a validation error', () => {
      it('returns false', () => {
        const mockGetters = {
          validationErrors: {
            assets: {
              links: {
                1: { isNameEmpty: true },
              },
            },
          },
        };

        expect(getters.isValid(state, mockGetters)).toBe(false);
      });
    });

    describe('when the tag name is empty', () => {
      it('returns false', () => {
        const mockGetters = {
          validationErrors: {
            isTagNameEmpty: true,
            assets: {
              links: {
                1: {},
              },
            },
          },
        };

        expect(getters.isValid(state, mockGetters)).toBe(false);
      });
    });
  });
});
