import { app, BrowserWindow, Event, LoadFileOptions, LoadURLOptions, NewWindowWebContentsEvent } from 'electron';
import os from 'os';
import path from 'path';
import { isDev } from '../../core/env';
import { ISessionHelper } from '../session/i-session-helper';
import { IAppWindow } from './i-app-window';
import BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions;

let defaultOptions: BrowserWindowConstructorOptions = {
  width: 1600,
  height: 900,
  webPreferences: {
    enableRemoteModule: false,
    nodeIntegration: false,
    contextIsolation: true,
    devTools: isDev(),
  },
};

switch (os.platform()) {
  case 'win32':
    defaultOptions = {
      ...defaultOptions,
      ...{
        icon: path.resolve(app.getAppPath(), 'resources', 'icon.ico'),
      },
    };
    break;
  default:
    break;
}

export abstract class AppWindow implements IAppWindow {
  protected static default = {};

  protected _window: BrowserWindow | null = null;

  protected readonly sessionHelper: ISessionHelper;

  protected options: BrowserWindowConstructorOptions;

  protected uri: string;

  protected abstract loadOptions: LoadFileOptions | LoadURLOptions;

  protected constructor(sessionHelper: ISessionHelper, uri: string, options: BrowserWindowConstructorOptions = {}) {
    this.sessionHelper = sessionHelper;
    this.options = { ...defaultOptions, ...options };
    this.uri = uri;
  }

  public get window(): BrowserWindow | null {
    return this._window;
  }

  public open(): Promise<void> {
    this._window = new BrowserWindow(this.options);

    this.sessionHelper.setCsp(this._window, this.getCsp());

    this._window.on('closed', () => {
      this._window = null;
    });

    if (isDev()) {
      this._window.webContents.openDevTools();
    }

    this._window.webContents.on('will-navigate', this.onWillNavigate);
    this._window.webContents.on('new-window', this.onNewWindow);

    return this.load(this._window);
  }

  public close(force: boolean = false): void {
    if (force) {
      this._window?.destroy();
    } else {
      this._window?.close();
    }
  }

  public isClosed(): boolean {
    return !this._window;
  }

  protected getCsp(): IContentSecurityPolicy {
    return {};
  }

  // eslint-disable-next-line @typescript-eslint/no-unused-vars -- it is used in child classes
  protected onWillNavigate(event: Event, navigationUrl: string): void {
    event.preventDefault();
  }

  protected onNewWindow(event: NewWindowWebContentsEvent): void {
    event.preventDefault();
  }

  protected abstract load(window: BrowserWindow): Promise<void>;
}
