/**
 * React hook for loading and mutating server settings and controls.
 */

import { useCallback, useEffect, useRef, useState } from "react";
import { fetchServerSettings, flushLogs, updateServerSettings } from "../api/server";
import { reloadConfig, restartFail2Ban } from "../api/config";
import { handleFetchError } from "../utils/fetchError";
import type { ServerSettings, ServerSettingsUpdate } from "../types/config";

export interface UseServerSettingsResult {
  settings: ServerSettings | null;
  loading: boolean;
  error: string | null;
  refresh: () => void;
  updateSettings: (update: ServerSettingsUpdate) => Promise<void>;
  flush: () => Promise<string>;
  reload: () => Promise<void>;
  restart: () => Promise<void>;
}

/**
 * Load server settings and provide control actions.
 */
export function useServerSettings(): UseServerSettingsResult {
  const [settings, setSettings] = useState<ServerSettings | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const abortRef = useRef<AbortController | null>(null);

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

    fetchServerSettings()
      .then((resp) => {
        if (!ctrl.signal.aborted) {
          setSettings(resp.settings);
        }
      })
      .catch((err: unknown) => {
        if (!ctrl.signal.aborted) {
          handleFetchError(err, setError, "Failed to fetch server settings");
        }
      })
      .finally(() => {
        if (!abortRef.current?.signal.aborted) {
          setLoading(false);
        }
      });
  }, []);

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

  const updateSettings = useCallback(
    async (update: ServerSettingsUpdate): Promise<void> => {
      await updateServerSettings(update);
      load();
    },
    [load],
  );

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

  const restart = useCallback(async (): Promise<void> => {
    await restartFail2Ban();
    load();
  }, [load]);

  const flush = useCallback(async (): Promise<string> => {
    return flushLogs();
  }, []);

  return {
    settings,
    loading,
    error,
    refresh: load,
    updateSettings,
    flush,
    reload,
    restart,
  };
}
