/**
 * React hook for loading and controlling the jail overview list.
 */

import { useCallback, useState } from "react";
import {
  fetchJails,
  reloadAllJails,
  reloadJail,
  setJailIdle,
  startJail,
  stopJail,
} from "../api/jails";
import { useListData } from "./useListData";
import type { JailSummary, JailListResponse } from "../types/jail";
import type { FetchError } from "../types/api";

export interface UseJailsResult {
  jails: JailSummary[];
  total: number;
  loading: boolean;
  error: FetchError | null;
  refresh: () => void;
  startJail: (name: string) => Promise<void>;
  stopJail: (name: string) => Promise<void>;
  setIdle: (name: string, on: boolean) => Promise<void>;
  reloadJail: (name: string) => Promise<void>;
  reloadAll: () => Promise<void>;
}

/**
 * Fetch and manage the jail overview list.
 */
export function useJails(): UseJailsResult {
  const [total, setTotal] = useState(0);

  const fetcher = useCallback(
    (signal: AbortSignal) => fetchJails(signal),
    [],
  );

  const selector = useCallback((response: JailListResponse) => response.items, []);

  const onSuccess = useCallback((response: JailListResponse) => {
    setTotal(response.total);
  }, []);

  const { items: jails, loading, error, refresh } = useListData<JailListResponse, JailSummary>({
    fetcher,
    selector,
    errorMessage: "Failed to load jails",
    onSuccess,
  });

  const startJailMemo = useCallback(
    async (name: string): Promise<void> => {
      await startJail(name);
      refresh();
    },
    [refresh],
  );

  const stopJailMemo = useCallback(
    async (name: string): Promise<void> => {
      await stopJail(name);
      refresh();
    },
    [refresh],
  );

  const reloadJailMemo = useCallback(
    async (name: string): Promise<void> => {
      await reloadJail(name);
      refresh();
    },
    [refresh],
  );

  const setIdleMemo = useCallback(
    (name: string, on: boolean): Promise<void> =>
      setJailIdle(name, on).then(() => {
        refresh();
      }),
    [refresh],
  );

  const reloadAllMemo = useCallback(
    (): Promise<void> =>
      reloadAllJails().then(() => {
        refresh();
      }),
    [refresh],
  );

  return {
    jails,
    total,
    loading,
    error,
    refresh,
    startJail: startJailMemo,
    stopJail: stopJailMemo,
    setIdle: setIdleMemo,
    reloadJail: reloadJailMemo,
    reloadAll: reloadAllMemo,
  };
}
