/*****************************************************************************
 * Open MCT, Copyright (c) 2014-2024, United States Government
 * as represented by the Administrator of the National Aeronautics and Space
 * Administration. All rights reserved.
 *
 * Open MCT is licensed under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 * Open MCT includes source code licensed under additional open source
 * licenses. See the Open Source Licenses file (LICENSES.md) included with
 * this source code distribution or the Licensing information page available
 * at runtime from the About dialog for additional information.
 *****************************************************************************/

/*
This test suite is dedicated to performance tests to ensure that testability of performance
is not broken upstream on Open MCT. Any assumptions made downstream will be tested here.

TODO:
 - Update resolution of performance config
 - Add Performance Observer on init to push all performance marks
 - Move client CDP connection to before or to a fixture

*/

import { expect, test } from '@playwright/test';

const notebookFilePath = 'test-data/PerformanceNotebook.json';

test.describe('Performance tests', () => {
  test.beforeEach(async ({ page, browser }, testInfo) => {
    // Go to baseURL
    await page.goto('./', { waitUntil: 'domcontentloaded' });

    // Click a:has-text("My Items")
    await page.locator('a:has-text("My Items")').click({
      button: 'right'
    });

    // Click text=Import from JSON
    await page.locator('text=Import from JSON').click();

    // Upload Performance Display Layout.json
    await page.setInputFiles('#fileElem', notebookFilePath);

    // TODO Fix this
    await page.locator('text=OK >> nth=1').click();

    await expect(page.locator('a:has-text("Performance Notebook")')).toBeVisible();

    //Create a Chrome Performance Timeline trace to store as a test artifact
    console.log('\n==== Devtools: startTracing ====\n');
    await browser.startTracing(page, {
      path: `${testInfo.outputPath()}-trace.json`,
      screenshots: true
    });
  });
  test.afterEach(async ({ page, browser }) => {
    console.log('\n==== Devtools: stopTracing ====\n');
    await browser.stopTracing();

    /* Measurement Section
        / The following section includes a block of performance measurements.
        */
    const startTime = await page.evaluate(() => window.performance.timing.navigationStart);
    console.log('window.performance.timing.navigationStart', startTime);

    //Get All Performance Marks
    const getAllMarksJson = await page.evaluate(() =>
      JSON.stringify(window.performance.getEntriesByType('mark'))
    );
    const getAllMarks = JSON.parse(getAllMarksJson);
    console.log('window.performance.getEntriesByType("mark")', getAllMarks);

    //Get All Performance Measures
    const getAllMeasuresJson = await page.evaluate(() =>
      JSON.stringify(window.performance.getEntriesByType('measure'))
    );
    const getAllMeasures = JSON.parse(getAllMeasuresJson);
    console.log('window.performance.getEntriesByType("measure")', getAllMeasures);
  });
  /* The following test will navigate to a previously created Performance Display Layout and measure the
    /  following metrics:
    /  - ElementResourceTiming
    /  - Interaction Timing
    */
  test('Notebook Search, Add Entry, Update Entry are performant', async ({ page, browser }) => {
    const client = await page.context().newCDPSession(page);
    // Tell the DevTools session to record performance metrics
    // https://chromedevtools.github.io/devtools-protocol/tot/Performance/#method-getMetrics
    await client.send('Performance.enable');
    // Go to baseURL
    await page.goto('./');

    // To to Search Available after Launch
    await page.locator('[aria-label="OpenMCT Search"] input[type="search"]').click();
    await page.evaluate(() => window.performance.mark('search-available'));
    // Fill Search input
    await page
      .locator('[aria-label="OpenMCT Search"] input[type="search"]')
      .fill('Performance Notebook');
    await page.evaluate(() => window.performance.mark('search-entered'));
    //Search Result Appears and is clicked
    await Promise.all([
      page.locator('a:has-text("Performance Notebook")').first().click(),
      page.evaluate(() => window.performance.mark('click-search-result'))
    ]);

    await page
      .locator('.c-tree__item c-tree-and-search__loading loading')
      .waitFor({ state: 'hidden' });
    await page.evaluate(() => window.performance.mark('search-spinner-gone'));

    await page.locator('.l-browse-bar__object-name').waitFor({ state: 'visible' });
    await page.evaluate(() => window.performance.mark('object-title-appears'));

    await page.locator('.c-notebook__entry >> nth=0').waitFor({ state: 'visible' });
    await page.evaluate(() => window.performance.mark('notebook-entry-appears'));

    // Click Add new Notebook Entry
    await page.locator('.c-notebook__drag-area').click();
    await page.evaluate(() => window.performance.mark('new-notebook-entry-created'));

    // Enter Notebook Entry text
    await page.getByLabel('Notebook Entry Input').last().fill('New Entry');
    await page.locator('.c-ne__save-button').click();
    await page.evaluate(() => window.performance.mark('new-notebook-entry-filled'));

    //Individual Notebook Entry Search
    await page.evaluate(() => window.performance.mark('notebook-search-start'));
    await page.locator('.c-notebook__search >> input').fill('Existing Entry');
    await page.evaluate(() => window.performance.mark('notebook-search-filled'));
    await page.locator('text=Search Results (3)').waitFor({ state: 'visible' });
    await page.evaluate(() => window.performance.mark('notebook-search-processed'));
    await page.locator('.c-notebook__entry >> nth=2').waitFor({ state: 'visible' });
    await page.evaluate(() => window.performance.mark('notebook-search-processed'));

    //Clear Search
    await page.locator('.c-search.c-notebook__search .c-search__input').hover();
    await page.locator('.c-search.c-notebook__search .c-search__clear-input').click();
    await page.evaluate(() => window.performance.mark('notebook-search-processed'));

    // Hover on Last
    await page.evaluate(() => window.performance.mark('new-notebook-entry-delete'));
    await page.locator('div.c-ne__time-and-content').last().hover();
    await page.locator('button[title="Delete this entry"]').last().click();
    await page.locator('button:has-text("Ok")').click();
    await page.locator('.c-notebook__entry >> nth=3').waitFor({ state: 'detached' });
    await page.evaluate(() => window.performance.mark('new-notebook-entry-deleted'));

    //await client.send('HeapProfiler.enable');
    await client.send('HeapProfiler.collectGarbage');

    let performanceMetrics = await client.send('Performance.getMetrics');
    console.log(performanceMetrics.metrics);
  });
});
