import axios from 'axios';
import { getQueryStringValue } from 'modules/query-string';
import { getState } from 'lib/redux/store';
import pickBy from 'lodash/pickBy';
import { message } from 'antd';

export const setRequestHeaders = (u?) => {
	axios.defaults.headers.common = {
		Accept: 'application/json',
		'Content-Type': 'application/json',
	};
	const userState = u ?? getState()['authReducer']?.userState;
	if (userState)
		axios.defaults.headers.common.Authorization = `Bearer ${userState?.data?.token}`;
};

setRequestHeaders();

interface RequestObject {
	url: string;
	options?: Record<string, any>;
	data?: any;
}

interface ResponseObject {
	data: any;
	pagination: any;
	message?: any;
}

export const parseResponse = (response: ResponseObject, nullable = false) => {
	if (response.message) {
		message.info(response.message);
	}

	if ((!response.data || typeof response.data !== 'object') && !nullable) {
		throw Error(
			'An error occurred while processing your request, please try again.',
		);
	} else if (nullable) {
		return { data: null };
	}
	if (response.data.data && response.data.current_page) {
		const data = response.data.data;
		response.pagination = (d => {
			d.data = null;
			return d;
		})(response.data);

		response.data = data;
	}

	const getPeripherals = item => {
		let ret = {};

		// include attributes
		if (item.attributes) ret = { ...ret, ...item.attributes };

		return ret;
	};

	if (Array.isArray(response.data)) {
		// res.data.data is an array
		response.data = response.data.map(item => ({
			id: item.id,
			...getPeripherals(item),
			...item,
		}));
	} else {
		// res.data.data is an object
		response.data = {
			id: response.data.id,
			...getPeripherals(response.data),
			...response.data,
		};
	}
	return response;
};

export const parseRequest = (request: Record<string, any>) => {

	if (request?.type) {
		request = {
			data: {
				id: request?.id,
				type: request.type,
				attributes: request,
			},
		};

		// remove type key from attributes object
		request.data.attributes = pickBy(
			request.data.attributes,
			function (value, key) {
				// return key !== 'name' && key !== 'description' && key !== 'status'
				return key !== 'type';
			},
		);
	}

	return request;
};

export const get = ({ url, data, options = {} }: RequestObject) => {
	setRequestHeaders();
	if (getQueryStringValue('page'))
		url += url.includes('?')
			? '&page=' + getQueryStringValue('page')
			: '?page=' + getQueryStringValue('page');
	if (getQueryStringValue('sort'))
		url += url.includes('?')
			? '&sort=' + getQueryStringValue('sort')
			: '?sort=' + getQueryStringValue('sort');
	if (data) {
		Object.entries(data).forEach(([key, value]) => {
			url += url.includes('?') ? `&${key}=${value}` : `?${key}=${value}`;
		});
	}

	let nullable = false;
	if (options.nullable) nullable = options.nullable;

	return new Promise((resolve, reject) => {
		try {
			resolve(
				axios
					.get<ResponseObject>(url, options)
					.then(res =>
						options.raw ? res : parseResponse(res.data, nullable),
					),
			);
		} catch (error: any) {
			if (error.response.data.message) {
				message.error(
					error.response.data.message ??
						'An error occurred while processing your request, please try again.',
					5,
				);
			}
			reject(error);
		}
	});
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const del = ({ url, data, options = {} }: RequestObject) => {
	setRequestHeaders();

	let nullable = true;
	if (options.nullable) nullable = options.nullable;

	return new Promise((resolve, reject) => {
		try {
			resolve(
				axios
					.delete<ResponseObject>(url, options)
					.then(res =>
						options.raw ? res : parseResponse(res.data, nullable),
					),
			);
		} catch (error: any) {
			if (error.response.data.message) {
				message.error(
					error.response.data.message ??
						'An error occurred while processing your request, please try again.',
					5,
				);
			}
			reject(error);
		}
	});
};

export const post = ({ url, data, options = {} }: RequestObject) => {
	setRequestHeaders();

	data = parseRequest(data);

	return new Promise((resolve, reject) => {
		try {
			resolve(
				axios
					.post<ResponseObject>(url, data, options)
					.then(res => (options.raw ? res : parseResponse(res.data))),
			);
		} catch (error: any) {
			if (error.response.data.message) {
				message.error(
					error.response.data.message ??
						'An error occurred while processing your request, please try again.',
					5,
				);
			}
			console.log('request.ts got error', error);
			reject(error);
		}
	});
};

export const patch = ({ url, data, options = {} }: RequestObject) => {
	setRequestHeaders();

	data = parseRequest(data);

	return new Promise((resolve, reject) => {
		try {
			resolve(
				axios
					.patch<ResponseObject>(url, data, options)
					.then(res => (options.raw ? res : parseResponse(res.data))),
			);
		} catch (error: any) {
			if (error.response.data.message) {
				message.error(
					error.response.data.message ??
						'An error occurred while processing your request, please try again.',
					5,
				);
			}
			reject(error);
		}
	});
};
