/*
 * Copyright (c) 2023 Eclipse Foundation, Inc.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * Contributors:
 *   Olivier Goulet <olivier.goulet@eclipse-foundation.org>
 *
 * SPDX-License-Identifier: EPL-2.0
 */

import { rest } from 'msw';
import { server } from './mocks/server';
import { mockInterestGroups } from './mocks/interest-groups/mock-data';
import * as membershipModule from '../../api/eclipsefdn.membership';
import * as interestGroupsModule from '../../api/eclipsefdn.interest-groups';

const { getInterestGroups, getInterestGroup, getInterestGroupParticipatingOrganizations } = interestGroupsModule;

describe('Projects API', () => {
  describe('Interest Groups', () => {
    let getOrganizationByIdSpy;

    beforeEach(() => {
      getOrganizationByIdSpy = jest.spyOn(membershipModule, 'getOrganizationById');
    });

    it('Fetches interest groups', async () => {
      const [interestGroups, error] = await getInterestGroups();
      
      const ids = interestGroups.map(interestGroup => interestGroup.shortProjectId).sort();
      const expectedIds = mockInterestGroups.model.map(interestGroup => interestGroup.shortProjectId).sort();

      expect(error).toBeNull();
      expect(ids).toEqual(expectedIds);
    });

    it('Returns an error if the API call fails', async () => {
      // Mock a 500 error
      server.use(
        rest.get('https://projects.eclipse.org/api/interest-groups', (_req, res, ctx) => {
          return res(
            ctx.status(500),
          );
        })
      );

      const [interestGroups, error] = await getInterestGroups();

      expect(error).not.toBeNull();
      expect(interestGroups).toBeNull();
    });

    it('Fetches an interest group by interest group id', async () => {
      // For simplicity, let's find the first interest group in our mock data.
      const interestGroupId = mockInterestGroups.model[0].shortProjectId;

      const [interestGroup, error] = await getInterestGroup({ interestGroupId });

      expect(error).toBeNull();
      expect(interestGroup.shortProjectId).toEqual(interestGroupId);
    });

    it('Fetches an interest group by interest group node id', async () => {
      // For simplicity, let's find the first interest group in our mock data.
      const interestGroupNodeId = mockInterestGroups.model[0].id;

      const [interestGroup, error] = await getInterestGroup({ interestGroupNodeId });
      
      expect(error).toBeNull();
      expect(interestGroup.id).toEqual(interestGroupNodeId);
    });

    it('Returns an error if no interest group id or node id is provided', async () => {
      const [interestGroup, error] = await getInterestGroup({});

      expect(error).not.toBeNull();
      expect(interestGroup).toBeNull();
    });

    it('Returns an error if the API call fails', async () => {
      const interestGroupId = mockInterestGroups.model[0].shortProjectId;

      // Mock a 500 error
      server.use(
        rest.get('https://projects.eclipse.org/api/interest-groups', (_req, res, ctx) => {
          return res(
            ctx.status(500),
          );
        })
      );
      server.use(
        rest.get('https://projects.eclipse.org/api/interest-groups/:interestGroupNodeId', (_req, res, ctx) => {
          return res(
            ctx.status(500),
          );
        })
      );

      // Test with interest group id
      let [interestGroup, error] = await getInterestGroup({ interestGroupId });

      expect(error.message).toContain('Could not fetch interest group for id');
      expect(interestGroup).toBeNull();

      // Test with interest group node id
      const interestGroupNodeId = mockInterestGroups.model[0].id;
      [interestGroup, error] = await getInterestGroup({ interestGroupNodeId });

      expect(error.message).toContain('Could not fetch interest group for node id');
      expect(interestGroup).toBeNull();
    });

    it('Fetches participating organizations for an interest group', async () => {
      const mockOrganization = {
        id: '1',
        name: 'Mock Organization',
      };

      getOrganizationByIdSpy.mockReturnValue([mockOrganization, null]);

      const interestGroupId = mockInterestGroups.model[0].shortProjectId;

      const [participatingOrganizations, error] = await getInterestGroupParticipatingOrganizations({ interestGroupId });

      expect(error).toBeNull();
      expect(participatingOrganizations.length).toBeGreaterThan(0);
    });

    it('Logs an error if participating organizations could not be fetched', async () => {
      const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
      getOrganizationByIdSpy.mockReturnValue([null, new Error('Something happened...')]);

      const interestGroupId = mockInterestGroups.model[0].shortProjectId;

      const [participatingOrganizations, error] = await getInterestGroupParticipatingOrganizations({ interestGroupId });

      expect(consoleSpy).toHaveBeenCalled();
      expect(Array.isArray(participatingOrganizations)).toBe(true);
      // We do not expect there to be an error if a single participating
      // organization could not be fetched among the many. We want to continue
      // rendering the ones that do work.
      expect(error).toBeNull();

      jest.restoreAllMocks();
    });
  });
});
