var noop = () => { };
var consoleLog = console.log;
var consoleCount = console.count;
var consoleError = console.error;

function matchLocal(urlToMatch, callback) {
  var rules = localStorage.getItem('rules') || '';

  var rlz = [];

  var arr = rules.split('\n').map(s => s.trim());
  for (var i = 0; i < arr.length; i += 4) {
    var url = skipFirstWord(arr[i + 0]);
    var pageElement = skipFirstWord(arr[i + 1]);
    var nextLink = skipFirstWord(arr[i + 2]);
    var emptyLine = arr[i + 3];

    var rx = new RegExp(url);
    if (rx.test(urlToMatch)) {
      rlz.push({
        url,
        pageElement,
        nextLink,
      })
    }
  }
  return callback(rlz);
}

function isBlacklisted(url) {
  var blacklist = localStorage.getItem('blacklist') || '';
  var urlRegExps = blacklist.split('\n').map(s => s.trim()).filter(Boolean);

  for (var i = 0; i < urlRegExps.length; i++) {
    var regexp = new RegExp(urlRegExps[i]);
    consoleLog(`testing "${url}" against "${urlRegExps[i]}"`);
    var isMatch = regexp.test(url);
    if (isMatch) {
      return true;
    }
  }

  return false;
}

function skipFirstWord(str) {
  if (!str) {
    return str;
  }

  var idx = str.indexOf(' ');
  return str.substring(idx + 1);
}

window.onload = async function () {
  var userToken = await getUserTokenOrGenerateNewToken();

  chrome.runtime.onMessage.addListener(async function (request, sender, sendResponse) {
    if (request) {
      if (request.type === `findUrlDescriptor`) {
        if (isBlacklisted(request.url)) {
          consoleLog(`url ${request.url} is blacklisted`);
          return sendResponse(null);
        }
        
        let browserInfo = await getBrowserInfo();
        fetch('http://127.0.0.1:8787/', { // 'https://next-page-server.ciborski.com/' 'http://localhost:30001/'
          method: 'post',
          body: request.url,
          headers: {
            'X-BrowserInfo': JSON.stringify(browserInfo),
            'Authorization': `Bearer ${userToken}`,
            'Version': '2.0.0',
          },
        }).then(response => {
          return response.text().then(text => {
            consoleLog(text);
            var resultsArray = JSON.parse(text)
            matchLocal(request.url, (rlz) => {
              resultsArray = resultsArray.concat(rlz);
              sendResponse(resultsArray);
            })
          })
        }).catch(error => {
          consoleLog(error);
          sendResponse(null);
        })
        return true;
      } else if (request.type === 'setStatus') {
        var { statusText, statusColorHex } = request;

        chrome.browserAction.setBadgeText({ text: statusText });
        chrome.browserAction.setBadgeBackgroundColor({ color: statusColorHex });

        sendResponse(null);
        return true;
      }

      return false;
    } else {
      chrome.runtime.Port.disconnect();
      return false;
    }
  });
}

function buildUrl(url, parameters) {
  let qs = "";
  for (const key in parameters) {
    if (parameters.hasOwnProperty(key)) {
      const value = parameters[key];
      qs +=
        encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
    }
  }
  if (qs.length > 0) {
    qs = qs.substring(0, qs.length - 1); //chop off last "&"
    url = url + "?" + qs;
  }

  return url;
}

async function getUserTokenOrGenerateNewToken() {
  return new Promise((resolve, reject) => {
    chrome.storage.sync.get(['userToken'], function (result) {
      if (result.userToken) {
        return resolve(result.userToken);
      } else {
        var userToken = getRandomToken();
        chrome.storage.sync.set({ userToken: userToken }, function () {
          return resolve(userToken);
        });
      }
    });
  })
}

function getRandomToken() {
  // E.g. 8 * 32 = 256 bits token
  var randomPool = new Uint8Array(32);
  crypto.getRandomValues(randomPool);
  var hex = '';
  for (var i = 0; i < randomPool.length; ++i) {
    hex += randomPool[i].toString(16);
  }
  // E.g. db18458e2782b2b77e36769c569e263a53885a9944dd0a861e5064eac16f1a
  return hex;
}

async function getUserAgentData() {
  let userAgentData = await window.navigator.userAgentData.getHighEntropyValues([
    'architecture',
    'bitness',
    'model',
    'platformVersion',
    'uaFullVersion',
    'fullVersionList',
    'wow64',
    'formFactor',
  ])
  return userAgentData;
}

async function getConnectionInfo() {
  return {
    downlink: window.navigator.connection.downlink,
    effectiveType: window.navigator.connection.effectiveType,
    rtt: window.navigator.connection.rtt,
    saveData: window.navigator.connection.saveData,
  };
}

async function getBrowserInfo() {
  let userAgentData = await getUserAgentData().catch(error => null);
  let connection = await getConnectionInfo().catch(error => null);
  let screen = {
    width: window.screen.width,
    height: window.screen.height,
    dpr: window.devicePixelRatio,
  }
  let viewport = {
    width: window.innerWidth,
    height: window.innerHeight,
  }
  let navigator = {
    appCodeName: window.navigator.appCodeName,
    appName: window.navigator.appName,
    appVersion: window.navigator.appVersion,
    deviceMemory: window.navigator.deviceMemory,
    doNotTrack: window.navigator.doNotTrack,
    hardwareConcurrency: window.navigator.hardwareConcurrency,
    language: window.navigator.language,
    languages: window.navigator.languages,
    maxTouchPoints: window.navigator.maxTouchPoints,
    onLine: window.navigator.onLine,
    pdfViewerEnabled: window.navigator.pdfViewerEnabled,
    platform: window.navigator.platform,
    product: window.navigator.product,
    productSub: window.navigator.productSub,
    userAgent: window.navigator.userAgent,
    vendor: window.navigator.vendor,
    vendorSub: window.navigator.vendorSub,
    webdriver: window.navigator.webdriver,
  };
  let browserInfo = {
    userAgentData,
    connection,
    screen,
    viewport,
    navigator,
  }
  return browserInfo;
}