/*!
 * Copyright (c) 2019, 2022, 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:
 *   Eric Poirier <eric.poirier@eclipse-foundation.org>
 *   Olivier Goulet <olivier.goulet@eclipse-foundation.org>
 *
 * SPDX-License-Identifier: EPL-2.0
 */

import parse from 'parse-link-header';
import { validateURL, transformSnakeToCamel } from './utils';
import { Adopter, ProjectWithAdopters } from '../types/models';
import 'isomorphic-fetch';

const apiBasePath = 'https://api.eclipse.org/adopters';

/**
  * Maps the adopter from the API response to the Adopter model. 
  *
  * @param adopter - The adopter object from the API response.
  * @returns The adopter object in the Adopter model format.
  */
const adopterMapper = (adopter: any): Adopter => {
  let mappedAdopter = transformSnakeToCamel(adopter) as any;

  mappedAdopter.logo = {
    default: mappedAdopter.logo,
    white: mappedAdopter.logoWhite,
  };

  delete mappedAdopter.logoWhite;
  
  return mappedAdopter as Adopter;
}

/**
  * Maps the project from the API response to the ProjectWithAdopters model.
  *
  * @param project - The project object from the API response.
  * @returns The project object in the ProjectWithAdopters model format.
  */
const projectWithAdoptersMapper = <T extends { adopters: unknown[] }>(project: T): ProjectWithAdopters => {
  // Ensure that the argument passed is of the expected type.
  if (!project.adopters || !Array.isArray(project.adopters)) {
    throw new TypeError('Unexpected type passed as argument of projectWithAdoptersMapper');
  }

  // Transform the project object from snake case to camel case.
  const tempProject = transformSnakeToCamel(project) as any;

  // Return the project object mapped with the expected model.
  return {
    ...tempProject,
    adopters: tempProject.adopters.map(adopterMapper),
  } as ProjectWithAdopters;
};

const getProjectsWithAdopters = async (workingGroup: string, projects: ProjectWithAdopters[] = [], nextUrl?: string): Promise<ProjectWithAdopters[]> => {
  let url;

  if (!nextUrl) {
    url = `${apiBasePath}/projects`;
    url += workingGroup ? `?working_group=${workingGroup}` : '';
  } else {
    url = nextUrl;
  }

  if (!validateURL(url)) return projects; 

  const response = await fetch(url);
  const data = await response.json();
  projects = projects.concat(data.map(projectWithAdoptersMapper));

  const linkHeader = parse(response.headers.get('Link'));
  if (linkHeader === undefined || linkHeader.next === undefined) return projects; 

  return getProjectsWithAdopters(workingGroup, projects, linkHeader.next.url);
};

export default getProjectsWithAdopters;
