const Backoff = require('./Backoff');
const Overlay = require('./discord_overlay2.node');
const {ipcMain, BrowserWindow} = require('electron');
const {
  OFFSCREEN_CLICK_ZONE_EVENT,
  OFFSCREEN_CURSOR_CHANGED,
  OFFSCREEN_INPUT_EVENT,
  OFFSCREEN_LOG,
  OFFSCREEN_START_DRAG,
  OFFSCREEN_STOP_DRAG,
  OFFSCREEN_WINDOW_UPDATE,
} = require('./events');

const overlayInstances = {};

ipcMain.on(OFFSCREEN_WINDOW_UPDATE, (event, args) => {
  if (!args.session) {
    return;
  }

  const session = args.session;
  let instance = overlayInstances[session];
  if (!instance) {
    instance = overlayInstances[session] = {
      sender: event.sender,
      ready: false,
      backoff: new Backoff(1000, 30000),
      loadFailed: false,
    };
  }

  if (args.destroy) {
    Overlay.destroyFramebuffer(session);
    if (instance.window) {
      instance.window.destroy();
    }
    if (instance.backoff) {
      instance.backoff.cancel();
    }

    delete overlayInstances[session];
    return;
  }

  if (args.frameBufferServer) {
    Overlay.createFramebuffer(session, args.frameBufferServer);
  }

  if (!instance.window) {
    instance.window = new BrowserWindow({
      show: false,
      skipTaskbar: true,
      webPreferences: {
        offscreen: true,
        transparent: true,
      },
    });

    instance.window.on('ready-to-show', () => {
      instance.ready = true;
      instance.sender.send(OFFSCREEN_LOG, `Overlay is ready to show`);
    });
    instance.window.webContents.on('did-fail-load', (e, errCode, errDesc, validatedURL) => {
      if (errCode === -3 || errCode === 0) return;
      instance.loadFailed = true;
      instance.sender.send(
        OFFSCREEN_LOG,
        `Failed overlay URL load (${validatedURL}) with code ${errCode} and description ${errDesc}`
      );
    });
    instance.window.webContents.on('did-finish-load', () => {
      if (instance.loadFailed) {
        instance.backoff.fail(() => {
          instance.sender.send(OFFSCREEN_LOG, `Retrying overlay URL load ${instance.url}`);
          instance.loadFailed = false;
          instance.window.loadURL(instance.url);
        });
      } else {
        instance.sender.send(OFFSCREEN_LOG, 'Overlay URL load succeeded');
        instance.backoff.succeed();
      }
    });
    instance.window.webContents.on('paint', (event, dirty, pixelBuffer, width, height, captureTimeUs) => {
      if (!instance.sender || !instance.ready) {
        return;
      }
      Overlay.commitFramebuffer(session, pixelBuffer, width, height, captureTimeUs);
    });
    instance.window.webContents.on('cursor-changed', (_event, type) => {
      if (!instance.sender) {
        return;
      }
      instance.sender.send(OFFSCREEN_CURSOR_CHANGED, session, type);
    });
    instance.window.webContents.on('start-drag', (_event, image, offset) => {
      if (!instance.sender) {
        return;
      }
      instance.sender.send(
        OFFSCREEN_START_DRAG,
        session,
        image ? image.toBitmap() : null,
        image ? image.getSize() : null,
        offset
      );
    });
    instance.window.webContents.on('stop-drag', _event => {
      if (!instance.sender) {
        return;
      }
      instance.sender.send(OFFSCREEN_STOP_DRAG, session);
    });
  }

  if (args.width > 0 && args.height > 0) {
    instance.window.setContentSize(args.width, args.height);
    instance.window.webContents.setFrameRate(60);
  } else {
    instance.window.webContents.setFrameRate(1);
  }

  if (args.url) {
    instance.url = args.url;
    instance.loadFailed = false;
    instance.window.loadURL(instance.url);
  }
});

ipcMain.on(OFFSCREEN_INPUT_EVENT, (event, args) => {
  if (!args.session || !overlayInstances[args.session]) {
    return;
  }

  const targetWindow = overlayInstances[args.session].window;
  if (targetWindow) {
    targetWindow.webContents.sendInputEvent(args.event);
  }
});

ipcMain.on(OFFSCREEN_CLICK_ZONE_EVENT, (event, args) => {
  if (!args.session || !overlayInstances[args.session] || !args.name) {
    return;
  }

  const targetWindow = overlayInstances[args.session].window;
  if (targetWindow) {
    targetWindow.webContents.send(OFFSCREEN_CLICK_ZONE_EVENT, args.name);
  }
});

module.exports = {};
