import type { DeviceId, DeviceInfo, FirmwareUpdateContext } from "@ledgerhq/types-live";

import { quitApp } from "../commands/quitApp";

import { from, Observable, of } from "rxjs";
import { switchMap, catchError } from "rxjs/operators";
import { SharedTaskEvent, sharedLogicTaskWrapper } from "./core";
import { getLatestFirmwareForDeviceUseCase } from "../../device/use-cases/getLatestFirmwareForDeviceUseCase";
import { withTransport } from "../transports/core";

export type GetLatestFirmwareTaskArgs = {
  deviceId: DeviceId;
  deviceName: string | null;
  deviceInfo: DeviceInfo;
};

export type GetLatestFirmwareTaskError = "FailedToRetrieveFirmwareUpdateInfo" | "FirmwareUpToDate";

export type GetLatestFirmwareTaskErrorEvent = {
  type: "taskError";
  error: GetLatestFirmwareTaskError;
};

export type GetLatestFirmwareTaskEvent =
  | { type: "data"; firmwareUpdateContext: FirmwareUpdateContext }
  | GetLatestFirmwareTaskErrorEvent
  | SharedTaskEvent;

function internalGetLatestFirmwareTask({
  deviceId,
  deviceName,
  deviceInfo,
}: GetLatestFirmwareTaskArgs): Observable<GetLatestFirmwareTaskEvent> {
  return new Observable(subscriber => {
    return withTransport(
      deviceId,
      deviceName ? { matchDeviceByName: deviceName } : undefined,
    )(({ transportRef }) =>
      quitApp(transportRef.current).pipe(
        switchMap(() => {
          return from(getLatestFirmwareForDeviceUseCase(deviceInfo));
        }),
        switchMap(firmwareUpdateContext => {
          if (firmwareUpdateContext) {
            return of<GetLatestFirmwareTaskEvent>({
              type: "data",
              firmwareUpdateContext,
            });
          } else {
            return of<GetLatestFirmwareTaskEvent>({
              type: "taskError",
              error: "FirmwareUpToDate",
            });
          }
        }),
        catchError(() => {
          return of<GetLatestFirmwareTaskEvent>({
            type: "taskError",
            error: "FailedToRetrieveFirmwareUpdateInfo",
          });
        }),
      ),
    ).subscribe(subscriber);
  });
}

export const getLatestFirmwareTask = sharedLogicTaskWrapper(internalGetLatestFirmwareTask);
