"use strict";

// preload.js for Electron app
const { ipcRenderer } = require('electron');
const fs = require('fs');
const _path = require('path');
const chokidar = require('chokidar');

const homeDirectory = require('os').homedir();
const wsroot = process.env.HOME_8BITWORKSHOP || _path.join(homeDirectory, '8bitworkshop');

function getLocalDir() {
  const _ui = window.ui_1 || window.ui || window; // TODO: module naming
  var dir = _ui.repo_id || _ui.platform_id || 'default';
  return _path.join(wsroot, dir);
}
function getLocalFilePath(path) {
  return _path.join(getLocalDir(), path);
}

function isProbablyBinary(path, data) {
  var score = 0;
  // decode as UTF-8
  for (var i = 0; i < (data?data.length:0);) {
    let c = data[i++];
    if ((c & 0x80) == 0) {
      // more likely binary if we see a NUL or obscure control character
      if (c < 9 || (c >= 14 && c < 26) || c == 0x7f) {
        score++;
        break;
      }
    } else {
      // look for invalid unicode sequences
      var nextra = 0;
      if ((c & 0xe0) == 0xc0) nextra = 1;
      else if ((c & 0xf0) == 0xe0) nextra = 2;
      else if ((c & 0xf8) == 0xf0) nextra = 3;
      else if (c < 0xa0) score++;
      else if (c == 0xff) score++;
      while (nextra--) {
        if (i >= data.length || (data[i++] & 0xc0) != 0x80) {
          score++;
          break;
        }
      }
    }
  }
  return score > 0;
}

// this is before startUI is called
process.once('loaded', () => {
  var watcher;
  var allfiles = new Set();
  // get workspace root dir
  // from browser: read workspace files asynchronously
  window.alternateLocalFilesystem = {
    getFileData: (path) => {
      let fullpath = getLocalFilePath(path);
      allfiles.add(fullpath);
      if (!fs.existsSync(fullpath)) {
        return null;
      }
      return new Promise( (resolve, reject) => {
        fs.readFile(fullpath, (err,buf) => {
          if (err) {
            resolve(err);
          } else {
            let isBinary = isProbablyBinary(path, buf);
            let data = isBinary ? buf : buf.toString('utf-8');
            console.log("getWorkspaceFile", path, isBinary, data.length);
            resolve(data);
          }
        });
      });
    },
    setFileData: (path, data) => {
      let fullpath = getLocalFilePath(path);
      allfiles.add(fullpath);
      let encoding = typeof data === 'string' ? 'utf8' : null;
      console.log("setWorkspaceFile", fullpath, data.length);
      return new Promise( (resolve, reject) => {
        fs.mkdir(_path.dirname(fullpath), {recursive:true}, (err,dirpath) => {
          fs.writeFile(fullpath, data, {encoding:encoding}, (err) => {
            if (err) {
              reject(err);
            } else {
              resolve();
            }
          });
        });
      });
    }
  }
  // watch/unwatch files as browser loses/gains focus
  window.addEventListener("blur", (e) => {
    let localdir = getLocalDir();
    if (!watcher && localdir) {
      // watch files for changes
      watcher = chokidar.watch(Array.from(allfiles), {
        //awaitWriteFinish: {pollInterval:50,stabilityThreshold:300},
        ignoreInitial: true
      });
      watcher.on('all', (event, path) => {
        path = path.substring(localdir.length + 1); //strip off prefix
        console.log('WATCH', event, path);
        // we don't use awaitWriteFinish b/c we might close() the watcher
        setTimeout(() => {
          window.reloadWorkspaceFile(path);
        }, 300);
      });
      console.log('watching', getLocalDir());
    }
  });
  window.addEventListener("focus", (e) => {
    if (watcher) {
      watcher.close();
      watcher = null;
    }
    console.log('stopped watching');
  });

  // from electron.js: set workspace root directory
  /*
  TODO
  ipcRenderer.on('setWorkspaceRoot', (event, data) => {
    wsroot = data.root;
    var binpath = _path.join(wsroot, 'bin');
    if (!fs.existsSync(binpath)) fs.mkdirSync(binpath, {});
    console.log('setWorkspaceRoot', wsroot);
  });
  // from electron.js: file changed
  ipcRenderer.on('fileChanged', (event, data) => {
    var path = data.path;
    window.reloadWorkspaceFile(path);
  });
  */
  console.log('loaded preload', window.alternateLocalFilesystem, window.startUI);
});
