import { getCorrelationId, getSessionId } from '@komi-app/correlation';
import { blobResponse, typedResponse, typedDataResponse, typedVoidResponse } from '@komi-app/typed-response';
import Cookies from 'js-cookie';
import { REFRESH_STATUS_CODE } from './constants.js';
import paramSerialize from './utils/serialize-params.js';
export class SDK {
    constructor(config) {
        this.config = config;
        this.profileId = '';
        this.toBody = (payload) => {
            return payload ? JSON.stringify(payload) : void 0;
        };
        this.toQuery = (payload) => {
            return payload ? paramSerialize(payload) : '';
        };
        this.toHeaders = (headers) => {
            const { setup } = this;
            return headers ? { ...setup.headers, ...headers } : setup.headers;
        };
        this.toHeadersCredentials = (payload) => {
            const { headers, body } = (payload || {});
            const credentials = this.setup.credentials;
            const toHeaders = this.toHeaders(headers);
            return {
                credentials,
                headers: {
                    ...toHeaders,
                    //When body is given, we assumes it will always be a json
                    ...(!!body && { 'content-type': 'application/json' })
                }
            };
        };
        // call refresh if status code matches refresh
        this.fetch = async (...args) => {
            const response = await fetch(...args);
            if (response.status !== REFRESH_STATUS_CODE) {
                return response;
            }
            await fetch(`${this.config.authUrl}/v1/refresh`, {
                credentials: 'include',
                method: 'POST'
            });
            return fetch(...args);
        };
        this.post = this.mutate('POST');
        this.put = this.mutate('PUT');
        this.patch = this.mutate('PATCH');
        this.blobResponse = blobResponse;
        this.typedResponse = typedResponse;
        this.typedDataResponse = typedDataResponse;
        this.typedVoidResponse = typedVoidResponse;
        this.targetUrl = config.targetUrl;
    }
    init(profileId) {
        this.profileId = profileId;
    }
    get setup() {
        const correlationId = getCorrelationId();
        const sessionId = getSessionId();
        const featureList = localStorage.getItem('featureList');
        const csrfToken = Cookies.get('KOMI_CSRF');
        const { config: { serviceName, serviceVersion }, profileId } = this;
        return {
            credentials: 'include',
            headers: {
                'x-service-name': serviceName,
                'x-service-version': serviceVersion,
                ...(profileId && { 'x-profile-id': profileId }),
                ...(correlationId && { 'x-correlation-id': correlationId }),
                ...(sessionId && { 'x-session-id': sessionId }),
                ...(featureList && { 'x-feature-list': featureList }),
                ...(csrfToken && { 'x-komi-csrf': csrfToken })
            }
        };
    }
    mutate(method) {
        return async (path, payload) => {
            const { toHeadersCredentials, toBody } = this;
            return this.fetch(`${this.targetUrl}${path}`, {
                //Use formData as body directly if given
                body: (payload === null || payload === void 0 ? void 0 : payload.formData) || toBody(payload === null || payload === void 0 ? void 0 : payload.body),
                method,
                ...toHeadersCredentials(payload)
            });
        };
    }
    async get(path, payload) {
        const { toHeadersCredentials, toQuery } = this;
        const params = toQuery(payload === null || payload === void 0 ? void 0 : payload.queryParams);
        return this.fetch(`${this.targetUrl}${path}${params}`, {
            method: 'GET',
            ...toHeadersCredentials(payload)
        });
    }
    async delete(path, payload) {
        const { toHeadersCredentials } = this;
        return this.fetch(`${this.targetUrl}${path}`, {
            method: 'DELETE',
            ...toHeadersCredentials(payload === null || payload === void 0 ? void 0 : payload.headers)
        });
    }
}
export default SDK;
