import { inject } from "inversify";
import { PrimariaApi } from "../../api/api";
import { PluginBusyList } from "../../api/plugin-busy-manager/plugin-busy-list/component";
import { PluginTask } from "../../api/plugin-busy-manager/plugin-busy-manager";
import { disposeShell, raiseCloseEvent, raiseCustomCloseEvent } from "../../disposer";
import { disposePlugins } from "../../handle-plugins";
import { TYPES } from "../../infrastructure/ioc/types";
import { translate } from "../../locales";
import { ExitShell } from "./request";

export class ExitShellHandler {
  constructor(@inject(TYPES.primaryApi) private api: PrimariaApi) {}
  async handle(exitEvent: ExitShell): Promise<void> {
    const evt = exitEvent && exitEvent.ecapEvent !== undefined ? exitEvent : undefined;

    try {
      const canExit = await this.api.exitGuardManager.canExit();
      if (!canExit) return;

      // Backwards-compat: external plugins still using the deprecated pluginBusyManager
      // would otherwise lose their exit-confirmation modal. Remove once all consumers migrate.
      const busyTasks = this.api.pluginBusyManager.getTasks();
      if (busyTasks.length > 0) {
        const { confirmed } = await this.askForClose(busyTasks);
        if (!confirmed) return;
      }

      // Per si un plugin tarda molt en fer dispose, màxim deixarem 5 segons, per no interrompre el tancar infinitament
      await Promise.race([
        disposePlugins(), // S'intenta executar un dispose normal
        this.timeout(10000), // Si passen 5s, es segueix amb l'execució
      ]);
      disposeShell();
      this.emitClose(evt);
    } catch (error) {
      this.api.notificationService.error(translate("errors.exit"));
      this.emitClose(evt);
    }
  }

  private timeout(ms: number) {
    return new Promise<void>((resolve) => setTimeout(resolve, ms));
  }

  private askForClose(busyTasks: PluginTask[]) {
    return this.api.interactionService.confirm(
      { busyTasks },
      { component: PluginBusyList },
      {
        title: translate("actions.askExit"),
        state: "error",
        confirmButtonText: "Sí",
        cancelButtonText: "No",
      },
    );
  }

  private emitClose(exitEvent?: ExitShell): void {
    if (exitEvent) {
      raiseCustomCloseEvent(exitEvent);
    } else {
      raiseCloseEvent();
    }
  }
}
