'use client';

import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
import { useRouter, useSearchParams, usePathname } from 'next/navigation';

/**
 * 검색 상태 필드 설정
 */
export interface SearchStateField {
  /** URL 쿼리 파라미터 키 */
  key: string;
  /** 기본값 */
  defaultValue: string;
}

export interface UseListSearchStateOptions {
  /** 관리할 검색 상태 필드들 (기본: search, tab) */
  fields?: SearchStateField[];
  /** URL 업데이트 디바운스 ms (기본: 300) */
  debounceMs?: number;
}

export interface UseListSearchStateReturn {
  /** 검색 상태 값 조회 */
  getValue: (key: string) => string;
  /** 검색 상태 값 변경 (URL 자동 동기화) */
  setValue: (key: string, value: string) => void;
  /** 현재 페이지 번호 */
  currentPage: number;
  /** 페이지 변경 */
  setPage: (page: number) => void;
  /** 전체 상태 초기화 */
  resetAll: () => void;
  /** 현재 목록 URL (쿼리 포함) — 상세페이지에서 돌아올 때 사용 */
  listUrl: string;
}

const DEFAULT_FIELDS: SearchStateField[] = [
  { key: 'search', defaultValue: '' },
  { key: 'tab', defaultValue: 'all' },
];

// ===== sessionStorage 헬퍼 =====
function getStorageKey(pathname: string): string {
  return `listSearch:${pathname}`;
}

function saveToStorage(pathname: string, state: Record<string, string>) {
  if (typeof window === 'undefined') return;
  try {
    sessionStorage.setItem(getStorageKey(pathname), JSON.stringify(state));
  } catch {
    // sessionStorage 용량 초과 등 무시
  }
}

function loadFromStorage(pathname: string): Record<string, string> | null {
  if (typeof window === 'undefined') return null;
  try {
    const raw = sessionStorage.getItem(getStorageKey(pathname));
    return raw ? JSON.parse(raw) : null;
  } catch {
    return null;
  }
}

/**
 * 리스트 페이지 검색 상태 보존 훅
 *
 * URL 쿼리파라미터 + sessionStorage 이중 저장으로
 * 상세 페이지 이동 후 돌아왔을 때 검색 상태가 유지됩니다.
 *
 * 우선순위: URL 파라미터 > sessionStorage > 기본값
 */
export function useListSearchState(
  options: UseListSearchStateOptions = {}
): UseListSearchStateReturn {
  const { fields = DEFAULT_FIELDS, debounceMs = 300 } = options;

  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();

  // fields를 ref로 안정화
  const fieldsRef = useRef(fields);
  fieldsRef.current = fields;

  // 초기값: URL 파라미터 > sessionStorage > 기본값
  const getInitialValues = (): Record<string, string> => {
    const values: Record<string, string> = {};
    let hasUrlParams = false;

    for (const field of fieldsRef.current) {
      const urlValue = searchParams?.get(field.key);
      if (urlValue !== null) {
        values[field.key] = urlValue;
        hasUrlParams = true;
      }
    }
    const urlPage = searchParams?.get('page');
    if (urlPage) hasUrlParams = true;

    // URL에 파라미터가 있으면 URL 우선
    if (hasUrlParams) {
      for (const field of fieldsRef.current) {
        if (values[field.key] === undefined) {
          values[field.key] = field.defaultValue;
        }
      }
      values._page = urlPage ?? '1';
      return values;
    }

    // URL에 없으면 sessionStorage 복원 시도
    const stored = loadFromStorage(pathname);
    if (stored) {
      return stored;
    }

    // 둘 다 없으면 기본값
    for (const field of fieldsRef.current) {
      values[field.key] = field.defaultValue;
    }
    values._page = '1';
    return values;
  };

  // 로컬 상태
  const [localState, setLocalState] = useState<Record<string, string>>(getInitialValues);

  // ref로 현재 상태 추적
  const stateRef = useRef(localState);
  stateRef.current = localState;

  // URL 업데이트 타이머 + 내부 업데이트 추적
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const isInternalUpdate = useRef(false);

  // URL → 로컬 상태 동기화 (브라우저 뒤로가기 대응)
  useEffect(() => {
    if (isInternalUpdate.current) {
      isInternalUpdate.current = false;
      return;
    }
    // URL에 파라미터가 없으면 sessionStorage에서 복원
    let hasUrlParams = false;
    for (const field of fieldsRef.current) {
      if (searchParams?.get(field.key) !== null) {
        hasUrlParams = true;
        break;
      }
    }
    if (searchParams?.get('page') !== null) hasUrlParams = true;

    let newValues: Record<string, string>;
    if (hasUrlParams) {
      newValues = {} as Record<string, string>;
      for (const field of fieldsRef.current) {
        newValues[field.key] = searchParams?.get(field.key) ?? field.defaultValue;
      }
      newValues._page = searchParams?.get('page') ?? '1';
    } else {
      const stored = loadFromStorage(pathname);
      if (stored) {
        newValues = stored;
        // sessionStorage에서 복원한 상태를 URL에도 반영
        queueMicrotask(() => syncToUrlImmediate(stored));
      } else {
        return; // 기본값이면 변경 불필요
      }
    }

    const current = stateRef.current;
    const isDifferent = Object.keys(newValues).some(
      (key) => newValues[key] !== current[key]
    );
    if (isDifferent) {
      setLocalState(newValues);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [searchParams]);

  // URL 즉시 업데이트 (디바운스 없이)
  const syncToUrlImmediate = useCallback(
    (state: Record<string, string>) => {
      isInternalUpdate.current = true;
      const params = new URLSearchParams();
      for (const field of fieldsRef.current) {
        const value = state[field.key];
        if (value && value !== field.defaultValue) {
          params.set(field.key, value);
        }
      }
      const page = state._page;
      if (page && page !== '1') {
        params.set('page', page);
      }
      const query = params.toString();
      const url = query ? `${pathname}?${query}` : pathname;
      router.replace(url, { scroll: false });
    },
    [pathname, router]
  );

  // 로컬 상태 → URL + sessionStorage 동기화 (디바운스)
  const syncToUrl = useCallback(
    (newState: Record<string, string>) => {
      // sessionStorage는 즉시 저장 (디바운스 없이)
      saveToStorage(pathname, newState);

      if (timerRef.current) clearTimeout(timerRef.current);
      timerRef.current = setTimeout(() => {
        syncToUrlImmediate(newState);
      }, debounceMs);
    },
    [pathname, debounceMs, syncToUrlImmediate]
  );

  // 값 조회
  const getValue = useCallback(
    (key: string): string => {
      return localState[key] ?? fieldsRef.current.find((f) => f.key === key)?.defaultValue ?? '';
    },
    [localState]
  );

  // 값 변경
  const setValue = useCallback(
    (key: string, value: string) => {
      setLocalState((prev) => {
        if (prev[key] === value) return prev;
        const next = { ...prev, [key]: value };
        if (key !== '_page') {
          next._page = '1';
        }
        queueMicrotask(() => syncToUrl(next));
        return next;
      });
    },
    [syncToUrl]
  );

  // 페이지
  const currentPage = parseInt(localState._page || '1', 10);
  const setPage = useCallback(
    (page: number) => {
      setValue('_page', String(page));
    },
    [setValue]
  );

  // 초기화
  const resetAll = useCallback(() => {
    const defaults: Record<string, string> = {};
    for (const field of fieldsRef.current) {
      defaults[field.key] = field.defaultValue;
    }
    defaults._page = '1';
    setLocalState(defaults);
    saveToStorage(pathname, defaults);
    isInternalUpdate.current = true;
    router.replace(pathname, { scroll: false });
  }, [pathname, router]);

  // 현재 목록 URL (쿼리 포함)
  const listUrl = useMemo(() => {
    const params = new URLSearchParams();
    for (const field of fieldsRef.current) {
      const value = localState[field.key];
      if (value && value !== field.defaultValue) {
        params.set(field.key, value);
      }
    }
    const page = localState._page;
    if (page && page !== '1') {
      params.set('page', page);
    }
    const query = params.toString();
    return query ? `${pathname}?${query}` : pathname;
  }, [localState, pathname]);

  // cleanup
  useEffect(() => {
    return () => {
      if (timerRef.current) clearTimeout(timerRef.current);
    };
  }, []);

  return {
    getValue,
    setValue,
    currentPage,
    setPage,
    resetAll,
    listUrl,
  };
}
