/*
 * 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 { getOrganizationById, getOrganizations, getProjectParticipatingOrganizations } from '../eclipsefdn.membership';
import { mockOrganizations, mockOrganizationsByProject } from './mocks/membership/mock-data';

const apiUrl = 'https://membership.eclipse.org/api';

describe('Membership API', () => {
  it('Fetches organization by id', async () => {
    const [organizations, error] = await getOrganizationById(656); 

    expect(error).toBeNull();
    expect(organizations.organizationId).toBe(656);
  });

  it('Should return an error if no id provided to getOrganizationById', async () => {
    // Suppress console.error output
    jest.spyOn(console, 'error').mockImplementation(() => {});

    const [organizations, error] = await getOrganizationById();

    expect(organizations).toBeNull();
    expect(error).not.toBeNull();

    // Restore console.error
    console.error.mockRestore();
  });

  it('Should return an error if organization id is not a valid number', async () => {
    // Suppress console.error output
    jest.spyOn(console, 'error').mockImplementation(() => {});

    const [organizations, error] = await getOrganizationById('not-a-number');

    expect(organizations).toBeNull();
    expect(error).not.toBeNull();

    // Restore console.error
    console.error.mockRestore();
  });

  it('Should return an error if no organization found for id', async () => {
    // Suppress console.error output
    jest.spyOn(console, 'error').mockImplementation(() => {});
    
    const [organizations, error] = await getOrganizationById(9999);

    expect(organizations).toBeNull();
    expect(error).not.toBeNull();

    // Restore console.error
    console.error.mockRestore(); 
  });

  it('Fetches all organizations', async () => {
    const [organizations, error] = await getOrganizations();

    expect(error).toBeNull();
    expect(organizations.length).toBe(mockOrganizations.length);
  });

  it('Should return an error if all organizations could not be fetched', async () => {
    // Suppress console.error output
    jest.spyOn(console, 'error').mockImplementation(() => {});

    // Mock a 500 error
    server.use(
      rest.get(`${apiUrl}/organizations`, (_, res, ctx) => {
        return res(
          ctx.status(500),
        );
      })
    );

    const [organizations, error] = await getOrganizations();

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

  it('Fetches all organizations for a particular working group', async () => {
    const [organizations, error] = await getOrganizations({ working_group: 'jakarta-ee' });

    expect(error).toBeNull();
    // Check that all organizations have a working group of jakarta-ee in their
    // WGPAs.
    expect(
      organizations.every(organization => 
        organization.wgpas.find(wgpa => wgpa.workingGroup === 'jakarta-ee')
      )
    ).toBe(true);
  });

  it('Fetches all organizations participating to a particular project', async () => {
    const [organizations, error] = await getProjectParticipatingOrganizations('ee4j');
    
    // Get the organization ids from the organizations array and sort them.
    // This will make it easier to compare the response and mock data.
    const organizationIds = organizations
      .map(organization => organization.organizationId)
      .sort();

    // Do the same with our mock values.
    const mockOrganizationIds = mockOrganizationsByProject['ee4j']
      .map(organization => organization.organization_id)
      .sort();

    // Sort the array so we can compare it to the mock data.
    expect(organizationIds).toEqual(mockOrganizationIds);
    expect(error).toBeNull();
  });

  it('Should return an error if no project provided to getProjectParticipatingOrganizations', async () => {
    // Suppress console.error output
    jest.spyOn(console, 'error').mockImplementation(() => {});

    const [organizations, error] = await getProjectParticipatingOrganizations();

    expect(organizations).toBeNull();
    expect(error).not.toBeNull();

    // Restore console.error
    console.error.mockRestore();
  });

  it('Should return an error if no project found when fetching project participating organizations', async () => {
    // Suppress console.error output
    jest.spyOn(console, 'error').mockImplementation(() => {});

    const [organizations, error] = await getProjectParticipatingOrganizations('non-existent-project');

    expect(organizations).toBeNull();
    expect(error).not.toBeNull();
    
    // Restore console.error
    console.error.mockRestore();
  });
});
