import { toast } from "react-toastify";
import { getToken } from "../Utils";

/**
 * Wrapper pro volání API, u kterých chceme automaticky zobrazit toaster s chybou ze serveru.
 * 
 * @param apiFunction volaná API funkce
 */
export function errorHandler<T>(apiFunction: () => Promise<T>): Promise<T> {
    return new Promise<T>((resolve, reject) => {
        apiFunction().then((result) => {
            resolve(result);
        }).catch(e => {
            toast.error(e.message, { theme: "colored" });
        });
    });
}

async function request<TResponse>(
    url: string,
    config: RequestInit = {}
): Promise<TResponse> {
    config.headers = config?.headers ? new Headers(config.headers) : new Headers();
    config.headers.set("Authorization", `Bearer ${getToken()}`);
    try {
        const response = await fetch(url, config);
        if (!response.ok) {
            // TODO tohle je blbě, jelikož automaticky očekáváme, že v případě chyby přijde vždy JSON, což není pravda
            const json = await response.json();
            // Vyhodíme samotnou hlášku z odpovědi, odchytí si jí errorHandler
            throw new Error(json.error);
        }
        const contentType = response.headers.get("content-type");
        if (contentType && contentType.indexOf("application/json") !== -1) {
            return response.json() as TResponse;
        } else {
            return response.text() as TResponse;
        }
    } catch (e) {
        return Promise.reject(e);
    }
}

async function blobRequest(
    url: string,
    config: RequestInit = {}
): Promise<Blob> {
    config.headers = config?.headers ? new Headers(config.headers) : new Headers();
    config.headers.set("Authorization", `Bearer ${getToken()}`);
    try {
        const response = await fetch(url, config);
        if (!response.ok) {
            const json = await response.json();
            // Vyhodíme samotnou hlášku z odpovědi, odchytí si jí errorHandler
            throw new Error(json.error);
        }
        return response.blob()
    } catch (e) {
        return Promise.reject(e);
    }
}

export const api = {
    get: <TResponse>(url: string) => request<TResponse>(url),
    blobGet: (url: string) => blobRequest(url),
    post: <TBody extends BodyInit, TResponse>(url: string, body: TBody) => request<TResponse>(url, { method: 'POST', body, headers: { 'Content-Type': 'application/json' } }),
}

export const getQrUrl = (login: string) => {
    return `/api/qr?login=${login}`;
}

export const getData = async (dayIndex?: number) => {
    let url = '/api/data';
    if (dayIndex != null) {
        url += '?dayIndex=' + dayIndex;
    }
    return await api.get<any>(url);
}

export const login = async (login?: string) => {
    return await api.post<any, any>('/api/login', JSON.stringify({ login }));
}
