import { BrowserWindow, screen } from "electron";
import { BaseWindowTracker } from "../../window-trackers";
import { WindowGeometry } from "../../types";

export function updateVisibleOverlayVisibilityService(args: {
  visibleOverlayVisible: boolean;
  mainWindow: BrowserWindow | null;
  windowTracker: BaseWindowTracker | null;
  trackerNotReadyWarningShown: boolean;
  setTrackerNotReadyWarningShown: (shown: boolean) => void;
  updateVisibleOverlayBounds: (geometry: WindowGeometry) => void;
  ensureOverlayWindowLevel: (window: BrowserWindow) => void;
  enforceOverlayLayerOrder: () => void;
  syncOverlayShortcuts: () => void;
}): void {
  if (!args.mainWindow || args.mainWindow.isDestroyed()) {
    return;
  }

  if (!args.visibleOverlayVisible) {
    args.mainWindow.hide();
    args.syncOverlayShortcuts();
    return;
  }

  if (args.windowTracker && args.windowTracker.isTracking()) {
    args.setTrackerNotReadyWarningShown(false);
    const geometry = args.windowTracker.getGeometry();
    if (geometry) {
      args.updateVisibleOverlayBounds(geometry);
    }
    args.ensureOverlayWindowLevel(args.mainWindow);
    args.mainWindow.show();
    args.mainWindow.focus();
    args.enforceOverlayLayerOrder();
    args.syncOverlayShortcuts();
    return;
  }

  if (!args.windowTracker) {
    args.setTrackerNotReadyWarningShown(false);
    args.ensureOverlayWindowLevel(args.mainWindow);
    args.mainWindow.show();
    args.mainWindow.focus();
    args.enforceOverlayLayerOrder();
    args.syncOverlayShortcuts();
    return;
  }

  if (!args.trackerNotReadyWarningShown) {
    args.setTrackerNotReadyWarningShown(true);
  }
  const cursorPoint = screen.getCursorScreenPoint();
  const display = screen.getDisplayNearestPoint(cursorPoint);
  const fallbackBounds = display.workArea;
  args.updateVisibleOverlayBounds({
    x: fallbackBounds.x,
    y: fallbackBounds.y,
    width: fallbackBounds.width,
    height: fallbackBounds.height,
  });
  args.ensureOverlayWindowLevel(args.mainWindow);
  args.mainWindow.show();
  args.mainWindow.focus();
  args.enforceOverlayLayerOrder();
  args.syncOverlayShortcuts();
}

export function updateInvisibleOverlayVisibilityService(args: {
  invisibleWindow: BrowserWindow | null;
  visibleOverlayVisible: boolean;
  invisibleOverlayVisible: boolean;
  windowTracker: BaseWindowTracker | null;
  updateInvisibleOverlayBounds: (geometry: WindowGeometry) => void;
  ensureOverlayWindowLevel: (window: BrowserWindow) => void;
  enforceOverlayLayerOrder: () => void;
  syncOverlayShortcuts: () => void;
}): void {
  if (!args.invisibleWindow || args.invisibleWindow.isDestroyed()) {
    return;
  }

  if (args.visibleOverlayVisible) {
    args.invisibleWindow.hide();
    args.syncOverlayShortcuts();
    return;
  }

  const showInvisibleWithoutFocus = (): void => {
    args.ensureOverlayWindowLevel(args.invisibleWindow!);
    if (typeof args.invisibleWindow!.showInactive === "function") {
      args.invisibleWindow!.showInactive();
    } else {
      args.invisibleWindow!.show();
    }
    args.enforceOverlayLayerOrder();
  };

  if (!args.invisibleOverlayVisible) {
    args.invisibleWindow.hide();
    args.syncOverlayShortcuts();
    return;
  }

  if (args.windowTracker && args.windowTracker.isTracking()) {
    const geometry = args.windowTracker.getGeometry();
    if (geometry) {
      args.updateInvisibleOverlayBounds(geometry);
    }
    showInvisibleWithoutFocus();
    args.syncOverlayShortcuts();
    return;
  }

  if (!args.windowTracker) {
    showInvisibleWithoutFocus();
    args.syncOverlayShortcuts();
    return;
  }

  const cursorPoint = screen.getCursorScreenPoint();
  const display = screen.getDisplayNearestPoint(cursorPoint);
  const fallbackBounds = display.workArea;
  args.updateInvisibleOverlayBounds({
    x: fallbackBounds.x,
    y: fallbackBounds.y,
    width: fallbackBounds.width,
    height: fallbackBounds.height,
  });
  showInvisibleWithoutFocus();
  args.syncOverlayShortcuts();
}

export function syncInvisibleOverlayMousePassthroughService(options: {
  hasInvisibleWindow: () => boolean;
  setIgnoreMouseEvents: (ignore: boolean, extra?: { forward: boolean }) => void;
  visibleOverlayVisible: boolean;
  invisibleOverlayVisible: boolean;
}): void {
  if (!options.hasInvisibleWindow()) return;
  if (options.visibleOverlayVisible) {
    options.setIgnoreMouseEvents(true, { forward: true });
  } else if (options.invisibleOverlayVisible) {
    options.setIgnoreMouseEvents(false);
  }
}

export function setVisibleOverlayVisibleService(options: {
  visible: boolean;
  setVisibleOverlayVisibleState: (visible: boolean) => void;
  updateVisibleOverlayVisibility: () => void;
  updateInvisibleOverlayVisibility: () => void;
  syncInvisibleOverlayMousePassthrough: () => void;
  shouldBindVisibleOverlayToMpvSubVisibility: () => boolean;
  isMpvConnected: () => boolean;
  setMpvSubVisibility: (visible: boolean) => void;
}): void {
  options.setVisibleOverlayVisibleState(options.visible);
  options.updateVisibleOverlayVisibility();
  options.updateInvisibleOverlayVisibility();
  options.syncInvisibleOverlayMousePassthrough();
  if (
    options.shouldBindVisibleOverlayToMpvSubVisibility() &&
    options.isMpvConnected()
  ) {
    options.setMpvSubVisibility(!options.visible);
  }
}

export function setInvisibleOverlayVisibleService(options: {
  visible: boolean;
  setInvisibleOverlayVisibleState: (visible: boolean) => void;
  updateInvisibleOverlayVisibility: () => void;
  syncInvisibleOverlayMousePassthrough: () => void;
}): void {
  options.setInvisibleOverlayVisibleState(options.visible);
  options.updateInvisibleOverlayVisibility();
  options.syncInvisibleOverlayMousePassthrough();
}
