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

import { useCallback, useEffect, useRef, useState } from "react";
import {
  fetchJails,
  reloadAllJails,
  reloadJail,
  setJailIdle,
  startJail,
  stopJail,
} from "../api/jails";
import { handleFetchError } from "../utils/fetchError";
import type { JailSummary } from "../types/jail";

export interface UseJailsResult {
  jails: JailSummary[];
  total: number;
  loading: boolean;
  error: string | 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 [jails, setJails] = useState<JailSummary[]>([]);
  const [total, setTotal] = useState(0);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const abortRef = useRef<AbortController | null>(null);

  const load = useCallback(() => {
    abortRef.current?.abort();
    const ctrl = new AbortController();
    abortRef.current = ctrl;
    setLoading(true);
    setError(null);

    fetchJails()
      .then((res) => {
        if (!ctrl.signal.aborted) {
          setJails(res.jails);
          setTotal(res.total);
        }
      })
      .catch((err: unknown) => {
        if (!ctrl.signal.aborted) {
          handleFetchError(err, setError, "Failed to load jails");
        }
      })
      .finally(() => {
        if (!ctrl.signal.aborted) {
          setLoading(false);
        }
      });
  }, []);

  useEffect(() => {
    load();
    return (): void => {
      abortRef.current?.abort();
    };
  }, [load]);

  const withRefresh =
    (fn: (name: string) => Promise<unknown>) =>
    async (name: string): Promise<void> => {
      await fn(name);
      load();
    };

  return {
    jails,
    total,
    loading,
    error,
    refresh: load,
    startJail: withRefresh(startJail),
    stopJail: withRefresh(stopJail),
    setIdle: (name, on) => setJailIdle(name, on).then(() => {
      load();
    }),
    reloadJail: withRefresh(reloadJail),
    reloadAll: () => reloadAllJails().then(() => {
      load();
    }),
  };
}
