const { mkdir, writeFile } = require('node:fs/promises')
  , path = require('path')
  , { By, until } = require('selenium-webdriver')
  , { JSDOM } = require('jsdom')
  , { HttpResponse } = require('selenium-webdriver/devtools/networkinterceptor')
  ;

global.takeScreenshot = async (driver) => {
  const dir = './test/screenshots';
  const fileName = path.relative(process.cwd(), __filename) + ' "' + global.expect.getState().currentTestName + `" ${new Date().toISOString()}.png`;
  const image = await driver.takeScreenshot();
  await mkdir(dir, { recursive: true });
  await writeFile(`${dir}/${fileName.replaceAll('/', '-')}`, image, 'base64');
};

global.url = (relativeOrAbsolute) => {
  const location = new URL(relativeOrAbsolute, global.testServerUrl);
  return location.href;
}

global.page = {
  waitUntilMapLoaded: async function (driver) {
    const mapPlaceholderEl = await driver.findElement(By.css('.map-placeholder'));
    await driver.wait(until.elementIsNotVisible(mapPlaceholderEl), 1000);
  },

  findElInFrame: async function (frame, locator) {
    const driver = frame.getDriver();
    await driver.switchTo().frame(frame);
    return driver.findElement(locator);
  },

  expectSelected: async function (el) {
    expect(await el.getAttribute('class')).toEqual(expect.stringContaining('selected'));
  },

  expectNotSelected: async function (el) {
    expect(await el.getAttribute('class')).toEqual(expect.not.stringContaining('selected'));
  },

  troopCounterSelector: function ({ allegiance = 'attacker', troopNumber = 1 } = {}) {
    return `.counter[data-allegiance="${allegiance}"][data-number="${troopNumber}"]`;
  },

  findMapResourceEl: function (driver) {
    return driver.findElement(By.css('object'));
  },

  findTroopRecordEl: function (driver) {
    return driver.findElement(By.css('.soldier-record'));
  }
};

global.mockResponse = async function mockResponse(driver, urlPath, template, buildFn) {
  const connection = driver.createCDPConnection('page');
  const dom = new JSDOM(template);
  const contents = buildFn(dom.window.document);

  const httpResponse = new HttpResponse(url(urlPath));
  httpResponse.body = contents;
  httpResponse.addHeaders('Content-Type', 'image/svg+xml');

  await driver.onIntercept(await connection, httpResponse, async () => {});
}

global.createTroopCounter = function (
  allegiance = 'attacker',
  troopNumber = 1,
  squadNumber = 1,
  weapon = 'rifle'
) {
  return JSDOM.fragment(`
    <g class="counter" data-allegiance="${allegiance}" data-number="${troopNumber}">
      <use class="primary-weapon" href="counters.svg#${weapon}"></use>
      <use class="troop-number" href="counters.svg#number-${troopNumber}"></use>
      <use class="squad-number" href="counters.svg#number-${squadNumber}"></use>
    </g>
  `);
}

global.placeCounter = function (document, counter, { q = 0, r = 0, s = 0, t = 0 } = {}) {
  document.querySelector(`[data-q="${q}"][data-r="${r}"][data-s="${s}"][data-t="${t}"]`).append(counter);
}

global.selectCounter = function (counter) {
  counter.querySelector('.counter').classList.add('selected');
  return counter;
}

global.svgDocument = function (document) {
  return `<?xml version="1.0" standalone="no"?>\n` + document.querySelector('svg').outerHTML;
}
