/*!
 * Copyright (c) 2021, 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, getNextPage } from '../utils/utils';

const eclipseProjectsUrl = "https://projects.eclipse.org/projects/";

const throwFetchError = ({ status, statusText } = response) => { 
    throw `${status}: ${statusText}` 
};

const getProjectsDataFromAPI = (url, projects = []) => {
  if (validateURL(url)) {
    return new Promise((resolve, reject) =>
      fetch(url)
        .then((response) => {
          if (response.status !== 200) throwFetchError(response);

          response
            .json()
            .then((data) => {
              projects = projects.concat(data);
              const linkHeader = parse(response.headers.get('Link'));
              if (linkHeader?.next && typeof linkHeader.next?.url === 'string') {
                getProjectsDataFromAPI(linkHeader.next.url, projects).then(resolve).catch(reject);
              } else {
                projects.forEach((project, key) => {
                  projects[key].version = 'none';
                  if (project.releases[0]) {
                    projects[key].version = project.releases[0].name;
                  }
                  if (typeof projects[key].website_url === "undefined" || projects[key].website_url === "") {
                    projects[key].website_url = eclipseProjectsUrl + projects[key].project_id;
                  }
                });

                projects.sort((a, b) => a.name.localeCompare(b.name));
                resolve(projects);
              }
            })
            .catch(reject);
        })
        .catch((err) => {
          reject(err);
        })
    );
  }
  
  // Return null if the URL is invalid.
  return null;
};


const getProjectsDataFromStaticSource = (url) => {
    // Return null if the URL is invalid.
    if (!validateURL(url)) return null;

    return new Promise((resolve, reject) => 
        fetch(url)
            .then(response => {
                if (response.status !== 200) throw `${response.status}: ${response.statusText}`
                
                response
                    .json()
                    .then((projects) => {
                      projects.forEach((_, key) => {
                          if (typeof projects[key].website_url === "undefined" || projects[key].website_url === "") {
                              projects[key].website_url = eclipseProjectsUrl + projects[key].project_id;
                          }
                      });

                      projects.sort((a, b) => a.name.localeCompare(b.name));
                      resolve(projects);
                    })
                    .catch(reject)
                })
            .catch((err) => reject(err))
    )
}

export const getProjectsData = (url, isStaticSource) => {
    let projects;

    if (isStaticSource) {
        projects = getProjectsDataFromStaticSource(url);
    } else {
        projects = getProjectsDataFromAPI(url);
    }

    return projects;
}

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

export const getProjectProposals = async (industryCollaborationId) => {
  try {
    let proposals = [];
    let nextPage = new URL(`${apiBasePath}/proposals`);
    if (industryCollaborationId) {
      nextPage.searchParams.set('industry_collaboration', industryCollaborationId);
    }

    while (nextPage) {
      const response = await fetch(nextPage.href);
      if (!response.ok) throw new Error('Could not retrieve project proposals');

      const data = await response.json();
      if (data?.result) {
        proposals = proposals.concat(data.result);
      }

      const linkHeader = response.headers.get('Link');
      nextPage = getNextPage(linkHeader);
    }

    return [proposals, null];
  } catch (error) {
    console.error(error);
    return [null, error];
  }
}

/**
  * Get the number of projects of the Eclipse Foundation or of a specific
  * industry collaboration.
  *
  * @param {string} industryCollaborationId - The ID of the industry
  * collaboration.
  *
  * @returns {Promise<[number, null] | [null, Error]>} The number of projects or an
  * error.
  */
export const getProjectCount = async (industryCollaborationId) => {
  try {
    let count = 0;
    let nextPage = new URL(`${apiBasePath}/projects?pagesize=100`);
    
    // Add industry collaboration filter if provided.
    if (industryCollaborationId) {
      nextPage.searchParams.set('industry_collaboration', industryCollaborationId);
    }

    // Fetch all pages and count projects.
    while (nextPage) {
      const response = await fetch(nextPage.href);
      if (!response.ok) throw new Error('Could not retrieve project count');

      const data = await response.json();
      count += data.length;

      // Get next page.
      const linkHeader = response.headers.get('Link');
      nextPage = getNextPage(linkHeader);
    }

    return [count, null];
  } catch (error) {
    console.error(error);
    return [null, error];
  }
};
