import path from 'path';
import sanitize from 'sanitize-filename';
import publisherUtils from '../core/reporter/publishers/publisher-utils.js';

export default async function setCommands(config) {
  browser.config = config;
  await browser.addCommand('jsSelectOption', async function () {
    await browser.execute(async function (el) {
      el.selected = 'selected';
      el.dispatchEvent(new Event('change'));
      el.parentElement.dispatchEvent(new Event('change'));
    }, this)
    await expect(this).toBeSelected();
  }, true)

  await browser.addCommand('jsClick', async function () {
    await browser.execute(async function (el) {
      await el.mouseover()
      await el.click()
    }, this)
  }, true)

  await browser.addCommand('jsSetValue', async function (value = "") {
    await browser.execute(async function (el, value) {
      el.value = value;
      el.dispatchEvent(new Event('change'));
    }, this, value)
  }, true)
  await browser.addCommand('getEnv', async function () {
    return browser.config.env;
  })
  browser.addCommand('focus', async function () {
    await browser.execute(async function (el) {
      el.focus();
    }, this);
  }, true);

  if (browser.config.automationProtocol && browser.config.automationProtocol == 'devtools') {

    await browser.addCommand('recursiveFindInFrames', async function (inputFrame, selector) {
      let frames = inputFrame.childFrames();
      let results = await Promise.all(
        frames.map(async frame => {
          let el = await frame.$x(selector);
          if (el) {
            return el[0];
          }
          if (frame.childFrames().length > 0) {
            return await browser.recursiveFindInFrames(frame, selector);
          }
          return null;
        })
      );
      return results.find(Boolean);
    })
    await browser.addCommand('findInFrames', async function (selector) {
      let puppeteerBrowser = await browser.getPuppeteer();
      let page = (await puppeteerBrowser.pages())[0];
      let result = await browser.recursiveFindInFrames(page.mainFrame(), selector);
      if (!result) {
        throw new Error(
          `The selector \`${selector}\` could not be found in any child frames.`
        );
      }
      return result;
    })
    await browser.addCommand('puppClick', async function () {
      let el = await browser.findInFrames(this.selector);
      await el.click();
    }, true)
    await browser.addCommand('puppSelect', async function (value) {
      let el = await browser.findInFrames(this.selector);
      await el.select(value);
    }, true)
    await browser.addCommand('puppScreenshot', async function () {
      let puppeteerBrowser = await browser.getPuppeteer();
      let page = (await puppeteerBrowser.pages())[0];
      let filename = sanitize('ScreenshotAt_' + publisherUtils.getDateAndTimeForFile() + '.png');
      let screenshotFile = path.join(screenshotPath, filename);
      await page.screenshot({
        path: screenshotFile,
        captureBeyondViewport: false
      });
      if (!browser.config.currentPuppScreenshots) {
        browser.config["currentPuppScreenshots"] = [];
      }
      browser.config.currentPuppScreenshots.push(screenshotFile);
    }, false)
    await browser.addCommand('puppElementScreenshot', async function () {
      let puppeteerBrowser = await browser.getPuppeteer();
      let page = (await puppeteerBrowser.pages())[0];
      let element = await browser.recursiveFindInFrames(page.mainFrame(), this.selector);
      if (!element) {
        throw new Error(
          `puppElementScreenshot: The selector \`${this.selector}\` could not be found in any child frames.`
        );
      }
      let filename = sanitize('ElementScreenshotAt_' + publisherUtils.getDateAndTimeForFile() + '.png');
      let screenshotFile = path.join(screenshotPath, filename);
      await element.screenshot({
        path: screenshotFile,
        captureBeyondViewport: false
      });
      if (!browser.config.currentPuppScreenshots) {
        browser.config["currentPuppScreenshots"] = [];
      }
      browser.config.currentPuppScreenshots.push(screenshotFile);
    }, true)
    await browser.overwriteCommand('uploadFile', async function (origUploadFileFunction, element, filePath) {
      let puppeteerBrowser = await browser.getPuppeteer();
      let page = (await puppeteerBrowser.pages())[0];
      let frames = await page.frames();
      let frameIndex = 0;
      if (browser.config.currentFrame !== "parent") { frameIndex = 1; }

      let input = (await frames[frameIndex].$x(element.selector))[0];
      await input.focus();
      await input.uploadFile(filePath);
    })
    await browser.overwriteCommand('click', async function (origCkickFunction) {
      try {
        await this.waitForClickable({ timeout: 1000 });
      } catch (error) {
        // ignore
      }
      return origCkickFunction();
    }, true)
    await browser.addCommand('pageClientSend', async function (option, arg) {
      let puppeteerBrowser = await browser.getPuppeteer();
      let page = (await puppeteerBrowser.pages())[0];
      let client = await page.target().createCDPSession();
      return client.send(option, arg);
    })
    await browser.addCommand('pageAuthenticate', async function (credentials) {
      let puppeteerBrowser = await browser.getPuppeteer();
      let page = (await puppeteerBrowser.pages())[0];
      return page.authenticate(credentials);
    })
  } else {
    await browser.overwriteCommand('uploadFile', async function (origUploadFileFunction, element, filePath) {
      let remoteFilePath = await origUploadFileFunction(filePath);
      await element.setValue(remoteFilePath);
    })
  }
}