/**
* @jest-environment jsdom
*/

/*!
 * 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 eclipsefdnProjects from '../eclipsefdn.projects';
import { generateMockProject, generateMockProposal } from '../../api/tests/mocks/projects/mock-data';
import * as projectsAPIModule from '../../api/eclipsefdn.projects';

const { projectMapper, proposalMapper } = projectsAPIModule;

describe('eclipsefdn-projects', () => {
  let getProjectsDataSpy;
  let getProjectProposalsSpy;

  beforeEach(() => {
    getProjectsDataSpy = jest.spyOn(projectsAPIModule, 'getProjectsData');
    getProjectProposalsSpy = jest.spyOn(projectsAPIModule, 'getProjectProposals');
  });

  afterAll(() => {
    jest.restoreAllMocks();
  });

  it('Renders static projects from a local JSON file', () => {
    getProjectsDataSpy.mockReturnValue([
      {
        "name": "Eclipse Che",
        "summary": "Eclipse Che is a Kubernetes-native IDE that makes Kubernetes development accessible for development teams, providing one-click developer workspaces and eliminating local environment configuration for your entire team.",
        "logo": "https://www.eclipse.org/che/images/che-logo-64.png",
        "tags": ["Tools"],
        "pmiUrl": "https://www.eclipse.org/che/",
        "version": "7.0.0",
        "state": "Active",
        "isProposal": false
      },
    ]);

    const staticSourceUrl = './static-projects.json';

    document.querySelector('body').innerHTML = `
      <div class="featured-projects" data-is-static-source="true" data-types="projects" data-url="${staticSourceUrl}"></div>
    `;

    eclipsefdnProjects.render();

    expect(getProjectsDataSpy).toHaveBeenCalledWith(staticSourceUrl, true);
  });

  it('Renders projects from an external source (ex. Projects API)', () => {
    getProjectsDataSpy.mockReturnValue([
      {
        "name": "Eclipse Che",
        "summary": "Eclipse Che is a Kubernetes-native IDE that makes Kubernetes development accessible for development teams, providing one-click developer workspaces and eliminating local environment configuration for your entire team.",
        "logo": "https://www.eclipse.org/che/images/che-logo-64.png",
        "tags": ["Tools"],
        "pmiUrl": "https://www.eclipse.org/che/",
        "version": "7.0.0",
        "state": "Active",
        "isProposal": false
      },
    ]);

    const url = 'https://api.eclipse.org/api/projects?working_group=internet-things-iot';

    document.querySelector('body').innerHTML = `
      <div class="featured-projects" data-is-static-source="false" data-types="projects" data-url="${url}"></div>
    `;

    eclipsefdnProjects.render();

    expect(getProjectsDataSpy).toHaveBeenCalledWith(url, false);
  });

  it('The page size option limits the number of projects displayed', async () => {
    const mockProjects = Array.from({ length: 5 }, () => generateMockProject());
    getProjectsDataSpy.mockReturnValue(mockProjects);

    const url = 'https://api.eclipse.org/api/projects?working_group=jakarta-ee';

    document.querySelector('body').innerHTML = `
      <div class="featured-projects" data-url="${url}" data-page-size="3"></div>
    `;

    await eclipsefdnProjects.render();

    const projectElements = document.querySelectorAll('.featured-projects-item');

    expect(projectElements).toHaveLength(3);
  });

  it('Sorting method allows for random sorting of projects', async () => {
    // Just checking whether or not the Math.random() function is called
    // is enough to ensure that the sorting method is random. It wouldn't
    // be practical to test randomness.
    let randomSpy = jest.spyOn(Math, 'random');
    const mockProjects = Array.from({ length: 5 }, () => generateMockProject({ industryCollaboration: 'Jakarta EE' })); 
    getProjectsDataSpy.mockReturnValue(mockProjects);

    const url = 'https://api.eclipse.org/api/projects?working_group=jakarta-ee';

    document.querySelector('body').innerHTML = `
      <div class="featured-projects" data-url="${url}" data-sorting-method="random"></div>
    `

    await eclipsefdnProjects.render();

    expect(randomSpy).toHaveBeenCalled();
  });

  it('Filters projects and project proposals using the includeStates option', async () => {
    const mockProjects = Array
      .from({ length: 5 }, () => generateMockProject())
      .concat([
        generateMockProject({ state: 'Incubating' }),
        generateMockProject({ state: 'Regular' }),
        generateMockProject({ state: 'Archived' }),
      ])
      .map(projectMapper);
    getProjectsDataSpy.mockReturnValue(mockProjects);

    const mockProposals = Array
      .from({ length: 5 }, () => generateMockProposal())
      .concat([
        generateMockProposal({ state: 'Created' }),
        generateMockProposal({ state: 'Draft' }),
        generateMockProject({ state: 'Archived' }),
      ])
      .map(proposalMapper);
    getProjectProposalsSpy.mockReturnValue([mockProposals, null]);

    const url = 'https://projects.eclipse.org/api/projects?working_group=jakarta-ee';

    document.body.innerHTML = `
      <div class="featured-projects" data-url="${url}" data-include-states="incubating">
      </div>
    `;

    await eclipsefdnProjects.render();

    let elements = Array.from(document.querySelectorAll('.project_state'));

    expect(elements.length).not.toBe(0);
    expect(elements.every((element) => element.innerHTML === 'Incubating')).toBe(true);

    document.body.innerHTML = `
      <div class="featured-projects" data-url="${url}" data-include-states="regular">
      </div>
    `;

    await eclipsefdnProjects.render();

    elements = Array.from(document.querySelectorAll('.project_state'));

    expect(elements.length).not.toBe(0);
    expect(elements.every((element) => element.innerHTML === 'Regular')).toBe(true);

  });

  it('Includes only active types of projects and proposals via the includeStates option', async () => {
    const mockProjects = Array
      .from({ length: 5 }, () => generateMockProject())
      .concat([
        generateMockProject({ state: 'Incubating' }),
        generateMockProject({ state: 'Regular' }),
        generateMockProject({ state: 'Archived' }),
      ])
    .map(projectMapper);
    getProjectsDataSpy.mockReturnValue(mockProjects);

    const mockProposals = Array
      .from({ length: 5 }, () => generateMockProposal())
      .concat([
        generateMockProposal({ state: 'Created' }),
        generateMockProposal({ state: 'Draft' }),
        generateMockProposal({ state: 'Withdrawn' }),
      ])
    .map(proposalMapper);
    getProjectProposalsSpy.mockReturnValue([mockProposals, null]);

    const url = 'https://projects.eclipse.org/api/projects?working_group=jakarta-ee';

    document.body.innerHTML = `
      <div class="featured-projects" data-url="${url}" data-include-states="active">
      </div>
    `;

    await eclipsefdnProjects.render();

    let elements = Array.from(document.querySelectorAll('.project_state'));

    expect(elements.length).not.toBe(0);
    expect(elements.every((element) => element.innerHTML !== 'Archived')).toBe(true);
    expect(elements.every((element) => element.innerHTML !== 'Withdrawn')).toBe(true);
  });

  it('Includes all types of projects and proposals via the includeStates option', async () => {
    const mockProjects = Array
      .from({ length: 5 }, () => generateMockProject())
      .concat([
        generateMockProject({ state: 'Incubating' }),
        generateMockProject({ state: 'Regular' }),
        generateMockProject({ state: 'Archived' }),
      ])
      .map(projectMapper);

    getProjectsDataSpy.mockReturnValue(mockProjects);

    const mockProposals = Array
      .from({ length: 5 }, () => generateMockProposal())
      .concat([
        generateMockProposal({ state: 'Created' }),
        generateMockProposal({ state: 'Draft' }),
        generateMockProject({ state: 'Archived' }),
      ])
      .map(proposalMapper);
    getProjectProposalsSpy.mockReturnValue([mockProposals, null]);

    const url = 'https://projects.eclipse.org/api/projects?working_group=jakarta-ee';

    document.body.innerHTML = `
      <div class="featured-projects" data-url="${url}" data-include-states="all">
      </div>
    `;

    await eclipsefdnProjects.render();

    let elements = Array.from(document.querySelectorAll('.project_state'));

    expect(elements.some((element) => element.innerHTML === 'Incubating')).toBe(true);
    expect(elements.some((element) => element.innerHTML === 'Regular')).toBe(true);
    expect(elements.some((element) => element.innerHTML === 'Archived')).toBe(true);
    expect(elements.some((element) => element.innerHTML === 'Created')).toBe(true);
    expect(elements.some((element) => element.innerHTML === 'Draft')).toBe(true);
  });
  
  it.skip('Filter out "created" proposals if both projects and proposals are displayed', async () => {

  });
});

