import logger from "@/logger.js";
import {useNotificationStore} from "@/store/notification.js";
import {config} from "@/config";
import {useActiveUserStore} from "@/store/activeuser.js";

const getCsrfToken = () => {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; XSRF-TOKEN=`);
    if (parts.length === 2) {
        return decodeURIComponent(parts.pop().split(';').shift());
    }
    return null;
}

const performRequest = async (requestingStore, method, url, body, expectResponse = true, expectedException = null) => {

    const params = {
        method: method,
        credentials: 'include',
        headers: {
            'Content-Type': 'application/json',
            'X-XSRF-TOKEN': getCsrfToken()
        }
    };

    if (body) {
        params.body = JSON.stringify(body);
    }

    const request = {url: url, params: params, expectResponse: expectResponse, expectedException: expectedException};
    logger.info("Request:", request);

    const resp = await executeRequest(requestingStore, request);

    logger.info("Response:", resp);
    return resp;
}

const performDownload = async (url, toFile, expectResponse = true, expectedException = null) => {

    const params = {
        method: 'GET',
        credentials: 'include',
        headers: {
            'X-XSRF-TOKEN': getCsrfToken()
        }
    };

    const request = {
        url: url,
        params: params,
        expectResponse: expectResponse,
        expectedException: expectedException,
        type: 'blob'
    };
    logger.info("Request:", request);

    const resp = await executeRequest(null, request);

    const downloadUrl = window.URL.createObjectURL(resp.data);

    // Create temporary link element and trigger download
    const link = document.createElement('a');
    link.href = downloadUrl;
    link.download = toFile;
    document.body.appendChild(link);
    link.click();

    // Clean up
    document.body.removeChild(link);
    window.URL.revokeObjectURL(downloadUrl);
}

const performUpload = async (url, file, expectResponse = true, expectedException = null) => {

    const formData = new FormData();
    formData.append('file', file);

    const params = {
        method: 'POST',
        credentials: 'include',
        headers: {
            'X-XSRF-TOKEN': getCsrfToken()
        },
        body: formData
    };

    const request = {url: url, params: params, expectResponse: expectResponse, expectedException: expectedException};
    logger.info("Request:", request);

    const resp = await executeRequest(null, request);

    logger.info("Response:", resp.data);
    return resp.data;
}

function handleErrorResponse(data, requestingStore, request) {
    const errorObj = {
        code: data.error.code,
        title: data.error.title,
        message: data.error.message,
        trace: data.error.trace
    }

    const error = new Error('Internal backend error');
    error.errorObj = errorObj;

    const errorStore = useNotificationStore();

    if (request.expectedException === null || (Array.isArray(request.expectResponse) && !request.expectedException.includes(data.error.title)) || (typeof request.expectedException === 'string' && data.error.title !== request.expectedException)) {
        logger.error(errorObj, request.expectedException);
        void errorStore.addError(errorObj, {store: requestingStore, request: request});
    } else {
        errorStore.addNotification({
            icon: 'warning',
            message: data.error.message,
            title: data.error.title,
            variant: 'exception',
        });
    }

    throw error;
}

const executeRequest = async (requestingStore, request) => {

    useActiveUserStore().trackActivity();


    const response = await fetch(request.url, request.params
    ).catch(e => {
        const error = {
            code: 'Network error.',
            message: "Please check your internet connection.",
            trace: null
        }

        logger.error(error, e);
        const errorStore = useNotificationStore();
        void errorStore.addError(error, {store: requestingStore, request: request});

        throw e;
    });

    if (response.status === 401) {
        logger.warn('Session expired, redirecting to login...');
        window.location.href = '/oauth2/authorization/azure';
        return Promise.reject(new Error('Session expired'));
    }

    let data = null;
    if (request.expectResponse) { // backend should return something
        try {
            if (request.type === 'blob' && response.ok) {
                data = await response.blob();
            } else {
                data = await response.json();
            }

        } catch (e) {
            const error = {
                code: 'Malformed response',
                message: "Malformed server response. Please contact support.",
                trace: null
            }

            logger.error(error);
            const errorStore = useNotificationStore();
            void errorStore.addError(error, {store: requestingStore, request: request});
            throw e;
        }

        if (!response.ok) {
            handleErrorResponse(data, requestingStore, request);
        }
    } else {
        if (!response.ok) {

            const data = await response.json().catch(_ => {
                const error = {
                    code: "Return code error " + response.status,
                    message: "Server returned wrong response code",
                    trace: null
                }
                logger.error(error);
                const errorStore = useNotificationStore();
                void errorStore.addError(error, {store: requestingStore, request: request});
                throw new Error('Internal backend error');

            });

            handleErrorResponse(data, requestingStore, request);
        }
    }

    return {data: data, headers: response.headers};
}

export default performRequest;
export {performUpload, performDownload, getCsrfToken};
