import { useRef, useCallback } from 'react';
import useSWR from '../../core/dist/index.mjs';
import { withMiddleware, useSWRConfig, useStateWithDeps, serialize, mergeObjects, getTimestamp, UNDEFINED, useIsomorphicLayoutEffect } from '../../_internal/dist/index.mjs';

const mutation = ()=>{
    return (key, fetcher, config = {})=>{
        const { mutate  } = useSWRConfig();
        const keyRef = useRef(key);
        const fetcherRef = useRef(fetcher);
        const configRef = useRef(config);
        // Ditch all mutation results that happened earlier than this timestamp.
        const ditchMutationsUntilRef = useRef(0);
        const [stateRef, stateDependencies, setState] = useStateWithDeps({
            data: UNDEFINED,
            error: UNDEFINED,
            isMutating: false
        });
        const currentState = stateRef.current;
        const trigger = useCallback(async (arg, opts)=>{
            const [serializedKey, resolvedKey] = serialize(keyRef.current);
            if (!fetcherRef.current) {
                throw new Error('Can’t trigger the mutation: missing fetcher.');
            }
            if (!serializedKey) {
                throw new Error('Can’t trigger the mutation: missing key.');
            }
            // Disable cache population by default.
            const options = mergeObjects(mergeObjects({
                populateCache: false,
                throwOnError: true
            }, configRef.current), opts);
            // Trigger a mutation, and also track the timestamp. Any mutation that happened
            // earlier this timestamp should be ignored.
            const mutationStartedAt = getTimestamp();
            ditchMutationsUntilRef.current = mutationStartedAt;
            setState({
                isMutating: true
            });
            try {
                const data = await mutate(serializedKey, fetcherRef.current(resolvedKey, {
                    arg
                }), // We must throw the error here so we can catch and update the states.
                mergeObjects(options, {
                    throwOnError: true
                }));
                // If it's reset after the mutation, we don't broadcast any state change.
                if (ditchMutationsUntilRef.current <= mutationStartedAt) {
                    setState({
                        data,
                        isMutating: false,
                        error: undefined
                    });
                    options.onSuccess == null ? void 0 : options.onSuccess(data, serializedKey, options);
                }
                return data;
            } catch (error) {
                // If it's reset after the mutation, we don't broadcast any state change
                // or throw because it's discarded.
                if (ditchMutationsUntilRef.current <= mutationStartedAt) {
                    setState({
                        error: error,
                        isMutating: false
                    });
                    options.onError == null ? void 0 : options.onError(error, serializedKey, options);
                    if (options.throwOnError) {
                        throw error;
                    }
                }
            }
        }, // eslint-disable-next-line react-hooks/exhaustive-deps
        []);
        const reset = useCallback(()=>{
            ditchMutationsUntilRef.current = getTimestamp();
            setState({
                data: UNDEFINED,
                error: UNDEFINED,
                isMutating: false
            });
        // eslint-disable-next-line react-hooks/exhaustive-deps
        }, []);
        useIsomorphicLayoutEffect(()=>{
            keyRef.current = key;
            fetcherRef.current = fetcher;
            configRef.current = config;
        });
        // We don't return `mutate` here as it can be pretty confusing (e.g. people
        // calling `mutate` but they actually mean `trigger`).
        // And also, `mutate` relies on the useSWR hook to exist too.
        return {
            trigger,
            reset,
            get data () {
                stateDependencies.data = true;
                return currentState.data;
            },
            get error () {
                stateDependencies.error = true;
                return currentState.error;
            },
            get isMutating () {
                stateDependencies.isMutating = true;
                return currentState.isMutating;
            }
        };
    };
};
/**
 * A hook to define and manually trigger remote mutations like POST, PUT, DELETE and PATCH use cases.
 *
 * @link https://swr.vercel.app/docs/mutation
 * @example
 * ```jsx
 * import useSWRMutation from 'swr/mutation'
 *
 * const {
 *   data,
 *   error,
 *   trigger,
 *   reset,
 *   isMutating
 * } = useSWRMutation(key, fetcher, options?)
 * ```
 */ var index = withMiddleware(useSWR, mutation);

export { index as default };
//# sourceMappingURL=index.mjs.map
