/**
 * React hook for fetching a single jail's detailed metadata.
 */

import { useCallback, useEffect, useRef, useState } from "react";
import { addIgnoreIp, delIgnoreIp, fetchJail, reloadJail, setJailIdle, startJail, stopJail, toggleIgnoreSelf as toggleIgnoreSelfApi } from "../api/jails";
import { handleFetchError } from "../utils/fetchError";
import type { Jail } from "../types/jail";

export interface UseJailDetailResult {
  jail: Jail | null;
  ignoreList: string[];
  ignoreSelf: boolean;
  loading: boolean;
  error: string | null;
  refresh: () => void;
  addIp: (ip: string) => Promise<void>;
  removeIp: (ip: string) => Promise<void>;
  toggleIgnoreSelf: (on: boolean) => Promise<void>;
  start: () => Promise<void>;
  stop: () => Promise<void>;
  reload: () => Promise<void>;
  setIdle: (on: boolean) => Promise<void>;
}

/**
 * Fetch and manage the detail view for a single jail.
 */
export function useJailDetail(name: string): UseJailDetailResult {
  const [jail, setJail] = useState<Jail | null>(null);
  const [ignoreList, setIgnoreList] = useState<string[]>([]);
  const [ignoreSelf, setIgnoreSelf] = useState(false);
  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);

    fetchJail(name)
      .then((res) => {
        if (!ctrl.signal.aborted) {
          setJail(res.jail);
          setIgnoreList(res.ignore_list);
          setIgnoreSelf(res.ignore_self);
        }
      })
      .catch((err: unknown) => {
        if (!ctrl.signal.aborted) {
          handleFetchError(err, setError, "Failed to fetch jail detail");
        }
      })
      .finally(() => {
        if (!ctrl.signal.aborted) {
          setLoading(false);
        }
      });
  }, [name]);

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

  const addIp = useCallback(async (ip: string): Promise<void> => {
    await addIgnoreIp(name, ip);
    load();
  }, [name, load]);

  const removeIp = useCallback(async (ip: string): Promise<void> => {
    await delIgnoreIp(name, ip);
    load();
  }, [name, load]);

  const toggleIgnoreSelf = useCallback(async (on: boolean): Promise<void> => {
    await toggleIgnoreSelfApi(name, on);
    load();
  }, [name, load]);

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

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

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

  const setIdle = useCallback(async (on: boolean): Promise<void> => {
    await setJailIdle(name, on);
    load();
  }, [name, load]);

  return {
    jail,
    ignoreList,
    ignoreSelf,
    loading,
    error,
    refresh: load,
    addIp,
    removeIp,
    toggleIgnoreSelf,
    start,
    stop,
    reload,
    setIdle,
  };
}
