import { Ref, ref, UnwrapRef } from 'vue';

interface IRequestHandler<formData, responseType> {
    before?: () => Promise<any>;
    request: (formData: formData) => Promise<responseType | void>;
    then?: (data: any) => Promise<any>;
    catch?: (err: any) => Promise<any>;
    finally?: () => Promise<any>;
}

// type TResponse<formData, responseType> = [
//     requestHandler: (formData?: formData) => Promise<responseType> | Promise<void>,
//     isLoading: Ref<boolean>,
//     isError: Ref<boolean>,
//     data: Ref<responseType | any>,
// ];

export default function <formData, responseType>(
    requester: IRequestHandler<formData, responseType>,
    isPreLoading = false,
): {
    isLoading: Ref<UnwrapRef<boolean>, UnwrapRef<boolean> | boolean>;
    requestHandler: (formData?: formData) => Promise<void>;
    isError: Ref<UnwrapRef<boolean>, UnwrapRef<boolean> | boolean>;
    data: Ref<any>;
} {
    const isLoading = ref(isPreLoading);
    const isError = ref(false);
    const data = ref();
    const requestHandler = async (formData: formData = {} as formData) => {
        requester.before && (await requester.before());

        isLoading.value = true;
        isError.value = false;

        try {
            data.value = await requester.request(formData);
            requester.then && (await requester.then(data.value as responseType));
            return data.value;
        } catch (err: any) {
            requester.catch && (await requester.catch(err));
            isError.value = true;
        } finally {
            isLoading.value = false;
            requester.finally && requester.finally();
        }
    };

    return { requestHandler, isLoading, isError, data };
}
