import _ from "lodash";

type FetchApiOptions = {
    method:
        | "POST"
        | "GET"
        | "DELETE"
        | "PUT"
        | "PATCH"
        | "post"
        | "get"
        | "delete"
        | "put"
        | "patch";
    body?: object | string;
    headers?: FetchHeader;
};

type FetchHeader = HeadersInit & {
    [key: string]: string | null;
};

export type FetchApiReturn = {
    success: boolean;
    payload: any;
    msg?: string;
    [key: string]: any;
};

/**
 * # Fetch API
 */
export default async function fetchApi(
    url: string,
    options?: FetchApiOptions,
    csrf?: boolean,
    /** Key to use to grab local Storage csrf value. */
    localStorageCSRFKey?: string
): Promise<any> {
    let data;

    const csrfValue = localStorage.getItem(localStorageCSRFKey || "csrf");

    let finalHeaders = {
        "Content-Type": "application/json",
    } as FetchHeader;

    if (csrf && csrfValue) {
        finalHeaders[`'${csrfValue.replace(/\"/g, "")}'`] = "true";
    }

    if (typeof options === "string") {
        try {
            let fetchData;

            switch (options) {
                case "post":
                    fetchData = await fetch(url, {
                        method: options,
                        headers: finalHeaders,
                    } as RequestInit);
                    data = fetchData.json();
                    break;

                default:
                    fetchData = await fetch(url);
                    data = fetchData.json();
                    break;
            }
        } catch (error: any) {
            console.log("FetchAPI error #1:", error.message);
            data = null;
        }
    } else if (typeof options === "object") {
        try {
            let fetchData;

            if (options.body && typeof options.body === "object") {
                let oldOptionsBody = _.cloneDeep(options.body);
                options.body = JSON.stringify(oldOptionsBody);
            }

            if (options.headers) {
                options.headers = _.merge(options.headers, finalHeaders);

                const finalOptions: any = { ...options };
                fetchData = await fetch(url, finalOptions);
            } else {
                const finalOptions = {
                    ...options,
                    headers: finalHeaders,
                } as RequestInit;

                fetchData = await fetch(url, finalOptions);
            }

            data = fetchData.json();
        } catch (error: any) {
            console.log("FetchAPI error #2:", error.message);
            data = null;
        }
    } else {
        try {
            let fetchData = await fetch(url);
            data = await fetchData.json();
        } catch (error: any) {
            console.log("FetchAPI error #3:", error.message);
            data = null;
        }
    }

    return data;
}
