import { useCallback, useEffect, useRef, useState } from 'react';
import { getApiCache } from './storage';

interface UseSWCOptions<T> {
    onError?: (e: unknown) => void;
    onLoad?: (data: T) => void;
    cacheOnly?: boolean;
    cacheTimeout?: number;
    autoStart?: boolean;
}

const DEFAULT_CACHE_TTL = 86400 * 120;

// 该 hook 在组件中按 key 和 action 拉取数据，自动处理加载/错误/缓存（stale-while-revalidate）
export function useSWC<T>(key: string, action: () => Promise<T>, options?: UseSWCOptions<T>) {
    const optionsRef = useRef(options || {});
    optionsRef.current = options || {};
    const keyRef = useRef(key);
    const [data, setData] = useState<T | null | undefined>(() =>
        getApiCache().getObject<T>(keyRef.current)
    );
    const [loading, setLoading] = useState<true | 'background' | false>(true);
    const [error, setError] = useState<unknown>(null);

    const actionRef = useRef(action);
    actionRef.current = action;

    const dataRef = useRef(data);
    dataRef.current = data;
    const isMountedRef = useRef(true);

    const load = useCallback(async () => {
        setLoading(dataRef.current ? 'background' : true);
        setError(null);
        const opts = optionsRef.current;
        const cacheKey = keyRef.current;
        try {
            const result = await actionRef.current();
            if (result) {
                getApiCache().setObject(cacheKey, result, opts.cacheTimeout || DEFAULT_CACHE_TTL);
            }
            if (isMountedRef.current) {
                opts.onLoad?.(result);
                setData(result);
                setLoading(false);
            }
        } catch (err) {
            if (isMountedRef.current) {
                opts.onError?.(err);
                setError(err);
                setLoading(false);
            }
        }
    }, []);

    useEffect(() => {
        isMountedRef.current = true;
        if (dataRef.current && optionsRef.current.cacheOnly) {
            setLoading(false);
            setError(null);
        } else if (optionsRef.current.autoStart !== false) {
            load();
        }
        return () => {
            isMountedRef.current = false;
        };
    }, [load]);

    const getOrLoad = useCallback(async () => {
        if (dataRef.current && optionsRef.current.cacheOnly) {
            setLoading(false);
            setError(null);
            return;
        }
        await load();
    }, [load]);

    return { data, loading, error, load: getOrLoad, refresh: load };
}
