/*****************************************************************************
 * 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 filePath = 'test-data/PerformanceDisplayLayout.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', filePath);

    // Click text=OK
    await page.locator('button:has-text("OK")').click();

    await expect(
      page.locator('a:has-text("Performance Display Layout Display Layout")')
    ).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.
        */
    //Get time difference between viewlarge actionability and evaluate time
    await page.evaluate(() =>
      window.performance.measure(
        'machine-time-difference',
        'viewlarge.start',
        'viewLarge.start.test'
      )
    );

    //Get StartTime
    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('Embedded View Large for Imagery is performant in Fixed Time', 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('./');

    // 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 Display Layout');
    await page.evaluate(() => window.performance.mark('search-entered'));
    //Search Result Appears and is clicked
    await Promise.all([
      page.waitForNavigation(),
      page.locator('a:has-text("Performance Display Layout")').first().click(),
      page.evaluate(() => window.performance.mark('click-search-result'))
    ]);

    //Time to Example Imagery Frame loads within Display Layout
    await page.locator('.c-imagery__main-image__bg').waitFor({ state: 'visible' });
    //Time to Example Imagery object loads
    await page.locator('.c-imagery__main-image__background-image').waitFor({ state: 'visible' });

    //Get background-image url from background-image css prop
    const backgroundImage = page.locator('.c-imagery__main-image__background-image');
    let backgroundImageUrl = await backgroundImage.evaluate((el) => {
      return window
        .getComputedStyle(el)
        .getPropertyValue('background-image')
        .match(/url\(([^)]+)\)/)[1];
    });
    backgroundImageUrl = backgroundImageUrl.slice(1, -1); //forgive me, padre
    console.log('backgroundImageurl ' + backgroundImageUrl);

    //Get ResourceTiming of background-image jpg
    const resourceTimingJson = await page.evaluate(
      (bgImageUrl) => JSON.stringify(window.performance.getEntriesByName(bgImageUrl).pop()),
      backgroundImageUrl
    );
    console.log('resourceTimingJson ' + resourceTimingJson);

    //Open Large view
    await page.locator('button:has-text("Large View")').click(); //This action includes the performance.mark named 'viewLarge.start'
    await page.evaluate(() => window.performance.mark('viewLarge.start.test')); //This is a mark only to compare evaluate timing

    //Time to Imagery Rendered in Large Frame
    await page.locator('.c-imagery__main-image__bg').waitFor({ state: 'visible' });
    await page.evaluate(() => window.performance.mark('background-image-frame'));

    //Time to Example Imagery object loads
    await page.locator('.c-imagery__main-image__background-image').waitFor({ state: 'visible' });
    await page.evaluate(() => window.performance.mark('background-image-visible'));

    // Get Current number of images in thumbstrip
    await expect(page.locator('.c-imagery__thumb').last()).toBeInViewport();
    const thumbCount = await page.locator('.c-imagery__thumb').count();
    console.log('number of thumbs rendered ' + thumbCount);
    await page.locator('.c-imagery__thumb').last().click();

    //Get ResourceTiming of all jpg resources
    const resourceTimingJson2 = await page.evaluate(() =>
      JSON.stringify(window.performance.getEntriesByType('resource'))
    );
    const resourceTiming = JSON.parse(resourceTimingJson2);
    const jpgResourceTiming = resourceTiming.find((element) => element.name.includes('.jpg'));
    console.log('jpgResourceTiming ' + JSON.stringify(jpgResourceTiming));

    // Click Close Icon
    await page.getByRole('button', { name: 'Close' }).click();
    await page.evaluate(() => window.performance.mark('view-large-close-button'));

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

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