import {
  SpinnerTypes,
  TerminalSpinner,
} from "https://deno.land/x/spinners@v1.1.2/mod.ts";

// deno-lint-ignore no-explicit-any
export interface SpinnerFor<Fn extends (...args: any[]) => any> {
  fn: Fn;
  text: string;
  done: (spinner: TerminalSpinner, result: Awaited<ReturnType<Fn>>) => void;
  error: (spinner: TerminalSpinner, error: Error) => void;
}

// deno-lint-ignore no-explicit-any
export async function spin<Fn extends (...args: any[]) => any>(
  options: SpinnerFor<Fn>,
  ...args: Parameters<Fn>
): Promise<ReturnType<Awaited<Fn>>> {
  const spinner = new TerminalSpinner({
    color: "blue",
    cursor: true,
    spinner: SpinnerTypes.arc,
    text: options.text,
  }).start();
  try {
    const result = await options.fn(...args);
    options.done(spinner, result);
    return result;
  } catch (error) {
    options.error(spinner, error);
    throw error;
  }
}

export default spin;
