import { parse } from '@brillout/json-serializer/parse';
import events from '#/src/events.js';

const postHeaders = {
	mode: 'cors',
	credentials: 'same-origin',
	headers: {
		'Content-Type': 'application/json',
	},
};

function getQuery(data) {
	if (!data) {
		return '';
	}

	const curatedQuery = Object.fromEntries(Object.entries(data).map(([key, value]) => (value === undefined ? null : [key, value])).filter(Boolean));

	return `?${new URLSearchParams(curatedQuery).toString()}`; // recode so commas aren't encoded
}

function showFeedback(isSuccess, options = {}, errorMessage) {
	if (!isSuccess && (typeof options.errorFeedback === 'string' || options.appendErrorMessage)) {
		events.emit('feedback', {
			type: 'error',
			message: options.appendErrorMessage && errorMessage
				? `${options.errorFeedback ? `${options.errorFeedback}: ` : ''}${errorMessage}`
				: options.errorFeedback,
		});

		return;
	}

	if (!isSuccess) {
		events.emit('feedback', {
			type: 'error',
			message: 'Error, please try again',
		});

		return;
	}

	if (isSuccess && options.successFeedback) {
		events.emit('feedback', {
			type: 'success',
			message: options.successFeedback,
		});

		return;
	}

	if (isSuccess && options.undoFeedback) {
		events.emit('feedback', {
			type: 'undo',
			message: options.undoFeedback,
		});
	}
}

export async function get(path, query = {}, options = {}) {
	try {
		const res = await fetch(`/api${path}${getQuery(query)}`);
		const body = parse(await res.text());

		if (res.ok) {
			showFeedback(true, options);
			return body;
		}

		showFeedback(false, options, body.statusMessage);
		throw new Error(body.statusMessage);
	}
	catch (error) {
		showFeedback(false, options, error.message);
		throw error;
	}
}

export async function post(path, data, options = {}) {
	try {
		const res = await fetch(`/api${path}${getQuery(options.query)}`, {
			method: 'POST',
			body: data && JSON.stringify(data),
			...postHeaders,
		});

		if (res.status === 204) {
			showFeedback(true, options);
			return null;
		}

		const body = parse(await res.text());

		if (res.ok) {
			showFeedback(true, options);
			return body;
		}

		showFeedback(false, options, body.statusMessage);
		throw new Error(body.statusMessage);
	}
	catch (error) {
		showFeedback(false, options, error.message);
		throw error;
	}
}

export async function patch(path, data, options = {}) {
	try {
		const res = await fetch(`/api${path}${getQuery(options.query)}`, {
			method: 'PATCH',
			body: data && JSON.stringify(data),
			...postHeaders,
		});

		if (res.status === 204) {
			showFeedback(true, options);
			return null;
		}

		const body = parse(await res.text());

		if (res.ok) {
			showFeedback(true, options);
			return body;
		}

		showFeedback(false, options, body.statusMessage);
		throw new Error(body.statusMessage);
	}
	catch (error) {
		showFeedback(false, options, error.message);
		throw error;
	}
}

export async function del(path, options = {}) {
	try {
		const res = await fetch(`/api${path}${getQuery(options.query)}`, {
			method: 'DELETE',
			body: options.data && JSON.stringify(options.data),
			...postHeaders,
		});

		if (res.status === 204) {
			showFeedback(true, options);
			return null;
		}

		const body = parse(await res.text());

		if (res.ok) {
			showFeedback(true, options);
			return body;
		}

		showFeedback(false, options, body.statusMessage);
		throw new Error(body.statusMessage);
	}
	catch (error) {
		showFeedback(false, options, error.message);
		throw error;
	}
}
