const Queue = require('queue');
const Chrome = require('chrome-remote-interface');

const concurrency = 1;
const iterations = 30;

const baseUrl = 'https://master.twitch.tech';

const paths = [
  '/',
  '/directory',
  '/dotamajor',
  '/directory/game/Dota%202'
]

let q = Queue({
  concurrency: concurrency
});
let status = {};

q.on('timeout', (next, job) => {
  console.log('Time out:', job);
});

q.on('success', (result, job) => {
  console.log('Done:', result);
});

const getBrowserClient = async ()=>{
  // NOTE: current implementation ONLY works with --headless
  const {webSocketDebuggerUrl} = await Chrome.Version();
  // connect to endpoint
  const browser = await Chrome({
      target: webSocketDebuggerUrl || 'ws://localhost:9222/devtools/browser'
  });

  // create a new context (incognito)
  const {Target} = browser;
  const {browserContextId} = await Target.createBrowserContext();
  const {targetId} = await Target.createTarget({
    url: 'about:blank',
    browserContextId
  });

  return Chrome({target: targetId});
};

const pageEventsSubmitted = async (client)=>{
  const browserCode = ()=>{
    return new Promise((fulfill, reject) => {
      let root = document.getElementById('root');
      let observer = new MutationObserver((mutations)=>{
        mutations.forEach((mutation)=>{
          if (mutation.type == 'attributes' && mutation.attributeName == 'data-a-page-events-submitted') {
            fulfill(true);
          }
        });
      });
      observer.observe(root, { attributes: true });

      // on the off chance that we were too slow getting our observer set up
      let attr = root.getAttribute('data-a-page-events-submitted');
      if (attr) fulfill(true);

      // don't wait more than 10 seconds
      setTimeout(()=>{
        console.log('pageEventsSubmitted timed out');
        reject(false);
      }, 10000);
    });
  };

  const {Runtime} = client;
  return await Runtime.evaluate({
    expression: `(${browserCode})()`,
    awaitPromise: true
  });
};

const pageLoadTest = async (path)=>{
  let url = `${baseUrl}${path}`;
  let results = {
    path: path,
    url: url,
    status: 1
  };

  // const client = await getBrowserClient(); // "incognito mode"
  const client = await Chrome();

  // extract domains
  const {Network, Page, DOM} = client;

  // log individual network requests, noisy AF
  // Network.requestWillBeSent((params) => {
  //   if (params.request.url.includes('tempo.cpe.wtf')) {
  //     console.log('Sending request to:', params.request.url);
  //     console.log(params.request);
  //   }
  // });

  // clear cache and cookies, not needed for "incognito"
  await Network.clearBrowserCache();
  await Network.clearBrowserCookies();

  // set a custom cookie with our test session id
  cookie =  await Network.setCookie({
    url: url,
    name: 'twilight.automation_session_id',
    domain: '.twitch.tech',
    value: process.env.SESSION_UUID,
    secure: true
  });

  // chrome network emulation, not entirely reliable
  // await Network.emulateNetworkConditions({
  //   offline: false,
  //   latency: 0,
  //   downloadThroughput: 512000,
  //   uploadThroughput: 56000
  // });

  await Promise.all([Network.enable(), Page.enable()]);

  setTimeout(()=>{
    if (client) client.close();
    return results;
  }, 60000);

  try {
    await Page.navigate({url: url});
    await Page.loadEventFired();
    const submission = await pageEventsSubmitted(client);

    if(submission.result.value) {
      status[path]++;
      results.status = 0;
    }

    await Page.navigate({url: 'about:blank'});
  } catch (err) {
    console.error(err);
  } finally {
    if (client) {
        await client.close();
    }
  }

  return results;
}

for(let i=0; i < paths.length; i++) {
  status[paths[i]] = 0;
  for(let j=0; j < iterations; j++) {
    q.push(()=>{
      let path = `${paths[i]}`
      return pageLoadTest(path);
    });
  }
}

q.start(()=>{
  console.log('Job queue finished');
  console.log('Status:', status);
  process.exit();
});
