import { useState, useEffect, useRef, type Dispatch, type SetStateAction } from 'react';

const PREFIX = 'wing';

function buildKey(userId: number, name: string): string {
  return `${PREFIX}:${userId}:${name}`;
}

function readStorage<T>(key: string, fallback: T): T {
  try {
    const raw = localStorage.getItem(key);
    if (raw === null) return fallback;
    return JSON.parse(raw) as T;
  } catch {
    return fallback;
  }
}

function writeStorage<T>(key: string, value: T): void {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch {
    // quota exceeded or unavailable — silent
  }
}

function resolveDefault<T>(d: T | (() => T)): T {
  return typeof d === 'function' ? (d as () => T)() : d;
}

/**
 * useState와 동일한 API, localStorage 자동 동기화.
 *
 * @param userId  null이면 일반 useState처럼 동작 (비영속)
 * @param name    설정 이름 (e.g. 'typeEnabled')
 * @param defaultValue  초기값 또는 lazy initializer
 * @param debounceMs    localStorage 쓰기 디바운스 (기본 300ms)
 */
export function usePersistedState<T>(
  userId: number | null,
  name: string,
  defaultValue: T | (() => T),
  debounceMs = 300,
): [T, Dispatch<SetStateAction<T>>] {
  const resolved = resolveDefault(defaultValue);

  const [state, setState] = useState<T>(() => {
    if (userId == null) return resolved;
    return readStorage(buildKey(userId, name), resolved);
  });

  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const stateRef = useRef(state);
  const userIdRef = useRef(userId);
  const nameRef = useRef(name);

  stateRef.current = state;
  userIdRef.current = userId;
  nameRef.current = name;

  // userId 변경 시 해당 사용자의 저장값 재로드
  useEffect(() => {
    if (userId == null) return;
    const stored = readStorage(buildKey(userId, name), resolved);
    setState(stored);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [userId]);

  // debounced write
  useEffect(() => {
    if (userId == null) return;
    const key = buildKey(userId, name);

    if (timerRef.current != null) clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => {
      writeStorage(key, state);
      timerRef.current = null;
    }, debounceMs);

    return () => {
      if (timerRef.current != null) {
        clearTimeout(timerRef.current);
        timerRef.current = null;
      }
    };
  }, [state, userId, name, debounceMs]);

  // unmount 시 pending write flush
  useEffect(() => {
    return () => {
      if (timerRef.current != null) {
        clearTimeout(timerRef.current);
        timerRef.current = null;
      }
      if (userIdRef.current != null) {
        writeStorage(buildKey(userIdRef.current, nameRef.current), stateRef.current);
      }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return [state, setState];
}
