import assert from 'node:assert/strict';
import test from 'node:test';
import { ensureOverlayWindowLevel, updateOverlayWindowBounds } from './overlay-window';
import {
  handleOverlayWindowBeforeInputEvent,
  handleOverlayWindowBlurred,
  isTabInputForMpvForwarding,
} from './overlay-window-input';

test('isTabInputForMpvForwarding matches bare Tab keydown only', () => {
  assert.equal(
    isTabInputForMpvForwarding({
      type: 'keyDown',
      key: 'Tab',
      code: 'Tab',
    } as Electron.Input),
    true,
  );
  assert.equal(
    isTabInputForMpvForwarding({
      type: 'keyDown',
      key: 'Tab',
      code: 'Tab',
      shift: true,
    } as Electron.Input),
    false,
  );
  assert.equal(
    isTabInputForMpvForwarding({
      type: 'keyUp',
      key: 'Tab',
      code: 'Tab',
    } as Electron.Input),
    false,
  );
});

test('handleOverlayWindowBeforeInputEvent forwards Tab to mpv for visible overlays', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBeforeInputEvent({
    kind: 'visible',
    windowVisible: true,
    input: {
      type: 'keyDown',
      key: 'Tab',
      code: 'Tab',
    } as Electron.Input,
    preventDefault: () => calls.push('prevent-default'),
    sendKeyboardModeToggleRequested: () => calls.push('keyboard-mode'),
    sendLookupWindowToggleRequested: () => calls.push('lookup-toggle'),
    tryHandleOverlayShortcutLocalFallback: () => {
      calls.push('fallback');
      return false;
    },
    forwardTabToMpv: () => calls.push('forward-tab'),
  });

  assert.equal(handled, true);
  assert.deepEqual(calls, ['prevent-default', 'forward-tab']);
});

test('handleOverlayWindowBeforeInputEvent leaves modal Tab handling alone', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBeforeInputEvent({
    kind: 'modal',
    windowVisible: true,
    input: {
      type: 'keyDown',
      key: 'Tab',
      code: 'Tab',
    } as Electron.Input,
    preventDefault: () => calls.push('prevent-default'),
    sendKeyboardModeToggleRequested: () => calls.push('keyboard-mode'),
    sendLookupWindowToggleRequested: () => calls.push('lookup-toggle'),
    tryHandleOverlayShortcutLocalFallback: () => {
      calls.push('fallback');
      return false;
    },
    forwardTabToMpv: () => calls.push('forward-tab'),
  });

  assert.equal(handled, false);
  assert.deepEqual(calls, []);
});

test('handleOverlayWindowBlurred skips visible overlay restacking after manual hide', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBlurred({
    kind: 'visible',
    windowVisible: true,
    isOverlayVisible: () => false,
    ensureOverlayWindowLevel: () => {
      calls.push('ensure-level');
    },
    moveWindowTop: () => {
      calls.push('move-top');
    },
  });

  assert.equal(handled, false);
  assert.deepEqual(calls, []);
});

test('handleOverlayWindowBlurred skips Windows visible overlay restacking after focus loss', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBlurred({
    kind: 'visible',
    windowVisible: true,
    isOverlayVisible: () => true,
    ensureOverlayWindowLevel: () => {
      calls.push('ensure-level');
    },
    moveWindowTop: () => {
      calls.push('move-top');
    },
    platform: 'win32',
  });

  assert.equal(handled, false);
  assert.deepEqual(calls, []);
});

test('handleOverlayWindowBlurred notifies Windows visible overlay blur callback without restacking', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBlurred({
    kind: 'visible',
    windowVisible: true,
    isOverlayVisible: () => true,
    ensureOverlayWindowLevel: () => {
      calls.push('ensure-level');
    },
    moveWindowTop: () => {
      calls.push('move-top');
    },
    onVisibleOverlayBlur: () => {
      calls.push('visible-blur');
    },
    platform: 'win32',
  });

  assert.equal(handled, false);
  assert.deepEqual(calls, ['visible-blur']);
});

test('handleOverlayWindowBlurred skips macOS visible overlay restacking after focus loss', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBlurred({
    kind: 'visible',
    windowVisible: true,
    isOverlayVisible: () => true,
    ensureOverlayWindowLevel: () => {
      calls.push('ensure-level');
    },
    moveWindowTop: () => {
      calls.push('move-top');
    },
    platform: 'darwin',
  });

  assert.equal(handled, false);
  assert.deepEqual(calls, []);
});

test('handleOverlayWindowBlurred skips Linux visible overlay restacking after focus loss', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBlurred({
    kind: 'visible',
    windowVisible: true,
    isOverlayVisible: () => true,
    ensureOverlayWindowLevel: () => {
      calls.push('ensure-level');
    },
    moveWindowTop: () => {
      calls.push('move-top');
    },
    platform: 'linux',
  });

  assert.equal(handled, false);
  assert.deepEqual(calls, []);
});

test('handleOverlayWindowBlurred notifies Linux visible overlay blur callback without restacking', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBlurred({
    kind: 'visible',
    windowVisible: true,
    isOverlayVisible: () => true,
    ensureOverlayWindowLevel: () => {
      calls.push('ensure-level');
    },
    moveWindowTop: () => {
      calls.push('move-top');
    },
    onVisibleOverlayBlur: () => {
      calls.push('visible-blur');
    },
    platform: 'linux',
  });

  assert.equal(handled, false);
  assert.deepEqual(calls, ['visible-blur']);
});

test('handleOverlayWindowBlurred notifies macOS visible overlay blur callback without restacking', () => {
  const calls: string[] = [];

  const handled = handleOverlayWindowBlurred({
    kind: 'visible',
    windowVisible: true,
    isOverlayVisible: () => true,
    ensureOverlayWindowLevel: () => {
      calls.push('ensure-level');
    },
    moveWindowTop: () => {
      calls.push('move-top');
    },
    onVisibleOverlayBlur: () => {
      calls.push('visible-blur');
    },
    platform: 'darwin',
  });

  assert.equal(handled, false);
  assert.deepEqual(calls, ['visible-blur']);
});

test('handleOverlayWindowBlurred preserves modal window stacking', () => {
  const calls: string[] = [];

  assert.equal(
    handleOverlayWindowBlurred({
      kind: 'modal',
      windowVisible: true,
      isOverlayVisible: () => false,
      ensureOverlayWindowLevel: () => {
        calls.push('ensure-modal');
      },
      moveWindowTop: () => {
        calls.push('move-modal');
      },
    }),
    true,
  );

  assert.deepEqual(calls, ['ensure-modal']);
});

test('ensureOverlayWindowLevel promotes Linux overlay above fullscreen mpv without changing workspaces', () => {
  const originalPlatformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
  Object.defineProperty(process, 'platform', {
    configurable: true,
    value: 'linux',
  });

  const calls: string[] = [];

  try {
    ensureOverlayWindowLevel({
      getTitle: () => 'SubMiner Overlay',
      moveTop: () => calls.push('move-top'),
      setAlwaysOnTop: (flag: boolean, level?: string, relativeLevel?: number) => {
        calls.push(`always-on-top:${flag}:${level ?? 'none'}:${relativeLevel ?? 0}`);
      },
      setVisibleOnAllWorkspaces: (flag: boolean, options?: { visibleOnFullScreen?: boolean }) => {
        calls.push(
          `all-workspaces:${flag}:${options?.visibleOnFullScreen === true ? 'fullscreen' : 'plain'}`,
        );
      },
    } as never);
  } finally {
    if (originalPlatformDescriptor) {
      Object.defineProperty(process, 'platform', originalPlatformDescriptor);
    }
  }

  assert.deepEqual(calls, [
    'always-on-top:true:screen-saver:1',
    'all-workspaces:true:fullscreen',
    'move-top',
  ]);
});

test('updateOverlayWindowBounds aligns Linux overlay content bounds to mpv geometry', () => {
  const originalPlatformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
  const originalHyprlandSignature = process.env.HYPRLAND_INSTANCE_SIGNATURE;
  Object.defineProperty(process, 'platform', {
    configurable: true,
    value: 'linux',
  });
  delete process.env.HYPRLAND_INSTANCE_SIGNATURE;

  const calls: Array<{ x: number; y: number; width: number; height: number }> = [];
  try {
    updateOverlayWindowBounds({ x: 0, y: 0, width: 3440, height: 1440 }, {
      isDestroyed: () => false,
      getTitle: () => 'SubMiner Overlay',
      getBounds: () => ({ x: 0, y: 0, width: 3440, height: 1440 }),
      getContentBounds: () => ({ x: 0, y: 14, width: 3440, height: 1426 }),
      setBounds: (bounds: { x: number; y: number; width: number; height: number }) => {
        calls.push(bounds);
      },
    } as never);
  } finally {
    if (originalPlatformDescriptor) {
      Object.defineProperty(process, 'platform', originalPlatformDescriptor);
    }
    if (originalHyprlandSignature === undefined) {
      delete process.env.HYPRLAND_INSTANCE_SIGNATURE;
    } else {
      process.env.HYPRLAND_INSTANCE_SIGNATURE = originalHyprlandSignature;
    }
  }

  assert.deepEqual(calls, [{ x: 0, y: -14, width: 3440, height: 1454 }]);
});
