import { firstValueFrom } from "rxjs";

import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";

import { BrowserStateService } from "../platform/services/abstractions/browser-state.service";

const IdleInterval = 60 * 5; // 5 minutes

export default class IdleBackground {
  private idle: typeof chrome.idle | typeof browser.idle | null;
  private idleTimer: number | NodeJS.Timeout = null;
  private idleState = "active";

  constructor(
    private vaultTimeoutService: VaultTimeoutService,
    private stateService: BrowserStateService,
    private notificationsService: NotificationsService,
    private accountService: AccountService,
  ) {
    this.idle = chrome.idle || (browser != null ? browser.idle : null);
  }

  async init() {
    if (!this.idle) {
      return;
    }

    const idleHandler = (newState: string) => {
      if (newState === "active") {
        // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
        // eslint-disable-next-line @typescript-eslint/no-floating-promises
        this.notificationsService.reconnectFromActivity();
      } else {
        // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
        // eslint-disable-next-line @typescript-eslint/no-floating-promises
        this.notificationsService.disconnectFromInactivity();
      }
    };
    if (this.idle.onStateChanged && this.idle.setDetectionInterval) {
      this.idle.setDetectionInterval(IdleInterval);
      this.idle.onStateChanged.addListener(idleHandler);
    } else {
      this.pollIdle(idleHandler);
    }

    if (this.idle.onStateChanged) {
      this.idle.onStateChanged.addListener(
        async (newState: chrome.idle.IdleState | browser.idle.IdleState) => {
          if (newState === "locked") {
            // Need to check if any of the current users have their timeout set to `onLocked`
            const allUsers = await firstValueFrom(this.accountService.accounts$);
            for (const userId in allUsers) {
              // If the screen is locked or the screensaver activates
              const timeout = await this.stateService.getVaultTimeout({ userId: userId });
              if (timeout === -2) {
                // On System Lock vault timeout option
                const action = await this.stateService.getVaultTimeoutAction({ userId: userId });
                if (action === VaultTimeoutAction.LogOut) {
                  await this.vaultTimeoutService.logOut(userId);
                } else {
                  await this.vaultTimeoutService.lock(userId);
                }
              }
            }
          }
        },
      );
    }
  }

  private pollIdle(handler: (newState: string) => void) {
    if (this.idleTimer != null) {
      globalThis.clearTimeout(this.idleTimer);
      this.idleTimer = null;
    }
    // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
    // eslint-disable-next-line @typescript-eslint/no-floating-promises
    this.idle.queryState(IdleInterval, (state: string) => {
      if (state !== this.idleState) {
        this.idleState = state;
        handler(state);
      }
      this.idleTimer = globalThis.setTimeout(() => this.pollIdle(handler), 5000);
    });
  }
}
