/*
 * Copyright (c) Jupyter Development Team.
 * Distributed under the terms of the Modified BSD License.
 */

const playwright = require('playwright');
const path = require('path');
const fs = require('fs');

// eslint-disable-next-line no-redeclare
const URL = process.argv[2];
const BROWSER_VAR = 'JLAB_BROWSER_TYPE';
const BROWSER = process.env[BROWSER_VAR] || 'chromium';
const OUTPUT_VAR = 'JLAB_BROWSER_CHECK_OUTPUT';
const OUTPUT = process.env[OUTPUT_VAR];

let nextScreenshot = 0;
const screenshotStem = `screenshot-${+new Date()}`;

if (OUTPUT) {
  console.log(`Screenshots will be saved in ${OUTPUT}...`);
  if (!fs.existsSync(OUTPUT)) {
    console.log(`Creating ${OUTPUT}...`);
    fs.mkdirSync(OUTPUT, { recursive: true });
  }
}

async function main() {
  /* eslint-disable no-console */
  console.info(`Starting headless ${BROWSER}...`);
  let testError = null;

  const pwBrowser = playwright[BROWSER];
  const browser = await pwBrowser.launch({
    logger: {
      isEnabled: () => !!OUTPUT,
      log: (name, severity, message, args) => console.log(name, message)
    }
  });

  const context = await browser.newContext();
  const page = await context.newPage();

  async function screenshot() {
    if (!OUTPUT) {
      return;
    }
    const screenshotPath = path.join(
      OUTPUT,
      `${screenshotStem}-${++nextScreenshot}.png`
    );
    console.log(`Capturing screenshot ${screenshotPath}...`);
    await page.screenshot({
      type: 'png',
      path: screenshotPath
    });
  }

  console.info('Navigating to page:', URL);
  await page.goto(URL);
  console.info('Waiting for page to load...');

  // Wait for the local file to redirect on notebook >= 6.0
  await page.waitForNavigation();

  console.log('Waiting for page content..');

  try {
    await page.locator('#jupyter-config-data').waitFor({ state: 'attached' });
  } catch (reason) {
    console.error('Error loading JupyterLab page:', reason);
    // Limit to 1000 characters
    console.error((await page.content()).substring(0, 1000));
    testError = reason;
  }

  console.log('Waiting for #main selector...');
  await page.waitForSelector('#main', { timeout: 100000 });

  console.log('Waiting for #browserTest selector...');
  const el = await page.waitForSelector('#browserTest', {
    timeout: 100000,
    state: 'attached'
  });
  console.log('Waiting for application to start...');

  try {
    await page.waitForSelector('.completed', { state: 'attached' });
  } catch (e) {
    testError = e;
  }

  await screenshot();

  const textContent = await el.getProperty('textContent');
  const errors = JSON.parse(await textContent.jsonValue());

  for (let error of errors) {
    console.error(`Parsed an error from text content: ${error.message}`, error);
    testError = true;
  }

  await browser.close();

  if (testError) {
    throw testError;
  }
  console.info('Browser test complete');
}

// Stop the process if an error is raised in the async function.
process.on('unhandledRejection', up => {
  throw up;
});

void main();
