import { getResourceReferenceFromAuraMethod } from '@talon/connect-gen/dist/forceChatterApi/util/util';
import { fetch } from 'talon/transport';

async function apiCall(endpoint, params) {
    const [controller, action] = endpoint.split('.');

    // handle Apex calls
    if (controller === 'ApexActionController') {
        return handleApexAction(action, params);
    }

    // handle UI API calls
    // get the UI API reference using the Aura controller and method name
    const uiApiReference = getResourceReferenceFromAuraMethod(endpoint);
    if (uiApiReference) {
        return handleUiApiCall(uiApiReference, params);
    }

    throw new Error(`Unsupported controller action: ${controller}.${action}`);
}

async function handleUiApiCall(
    { urlPath, urlPathParamNames, method, inputRepresentation },
    params
) {
    const remainingParams = (params && { ...params }) || {};

    // replace the path params
    let path = urlPathParamNames.reduce((currentPath, paramName) => {
        const value = remainingParams[paramName];
        delete remainingParams[paramName];
        return currentPath.replace(`\${${paramName}}`, encodeURIComponent(value));
    }, urlPath);

    // get the POST/PATCH body
    let body;
    if ((method === 'POST' || method === 'PATCH') && remainingParams[inputRepresentation]) {
        body = JSON.stringify(remainingParams[inputRepresentation]);
        delete remainingParams[inputRepresentation];
    }

    // add the rest as query params
    if (Object.keys(remainingParams).length) {
        path += `?${Object.entries(remainingParams)
            .filter(([, val]) => {
                return val !== undefined && val !== null && (!Array.isArray(val) || val.length);
            })
            .map(([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`)
            .join('&')}`;
    }

    // fetch!
    return fetch(path, { method, body }).then(response => {
        if (!response.ok) {
            throw response.statusText; // eslint-disable-line no-throw-literal
        }
        return response.status !== 204 && response.json();
    });
}

async function handleApexAction(action, params) {
    if (action === 'execute') {
        return fetch(`/apex/${action}`, {
            method: 'POST',
            body: JSON.stringify(params),
        })
            .then(response => {
                // we always resolve to a json... if there are errors, they
                // are exposed and thrown from the error property
                // see lds/transport-utils#createFetchResponse()
                return response.status !== 204 ? response.json() : undefined;
            })
            .then(response => {
                if (response && response.error && response.error.length > 0) {
                    throw response.error[0]; // eslint-disable-line no-throw-literal
                }

                return response;
            });
    }

    throw new Error(`Unsupported Apex action: ${action}`);
}

export { apiCall };
