import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import {
  getSettings,
  saveSettings,
  type SettingsState,
  SETTINGS_DEFAULTS,
} from '../services/settings';

export interface UseSettingsFormReturn {
  settings: SettingsState;
  updateSetting: <K extends keyof SettingsState>(key: K, value: SettingsState[K]) => void;
  isDirty: boolean;
  changedFields: Set<string>;
  save: () => Promise<void>;
  discard: () => void;
  isSaving: boolean;
  isLoading: boolean;
  error: string | null;
}

export function useSettingsForm(): UseSettingsFormReturn {
  const [settings, setSettings] = useState<SettingsState>(SETTINGS_DEFAULTS);
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const initialStateRef = useRef<SettingsState>(SETTINGS_DEFAULTS);

  useEffect(() => {
    let cancelled = false;

    async function load() {
      try {
        setIsLoading(true);
        setError(null);
        const data = await getSettings();
        if (!cancelled) {
          setSettings(data);
          initialStateRef.current = data;
        }
      } catch (err) {
        if (!cancelled) {
          setError(err instanceof Error ? err.message : 'Failed to load settings');
        }
      } finally {
        if (!cancelled) {
          setIsLoading(false);
        }
      }
    }

    load();
    return () => {
      cancelled = true;
    };
  }, []);

  const updateSetting = useCallback(
    <K extends keyof SettingsState>(key: K, value: SettingsState[K]) => {
      setSettings((prev) => ({ ...prev, [key]: value }));
    },
    [],
  );

  const changedFields = useMemo(() => {
    const changed = new Set<string>();
    const initial = initialStateRef.current;
    for (const key of Object.keys(initial) as (keyof SettingsState)[]) {
      if (settings[key] !== initial[key]) {
        changed.add(key);
      }
    }
    return changed;
  }, [settings]);

  const isDirty = changedFields.size > 0;

  const save = useCallback(async () => {
    try {
      setIsSaving(true);
      setError(null);
      const saved = await saveSettings(settings);
      setSettings(saved);
      initialStateRef.current = saved;
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to save settings');
      throw err;
    } finally {
      setIsSaving(false);
    }
  }, [settings]);

  const discard = useCallback(() => {
    setSettings(initialStateRef.current);
  }, []);

  return {
    settings,
    updateSetting,
    isDirty,
    changedFields,
    save,
    discard,
    isSaving,
    isLoading,
    error,
  };
}
