import { getIn } from "herculex/dist/utils/manipulate";
import { host, getTicketUrl, ywtRequestUrl, terminal } from "./constants";
import { getSilentAuthCode, getAppId, getServerTime } from "./jsapi";
import { joinUrl } from "./format";

function showErrorMessgage({ isShowError, error }) {
	if (isShowError) {
		my.showToast({
			type: "fail",
			content: error && (error.msg || error.errorMessage),
			duration: 3000,
		});
	}
}

async function checkTimeExpire(time) {
	if (!time) return false;
	const [err, res] = await getServerTime();
	const currentTime = err ? new Date().getTime() : +res.time;
	return time < currentTime;
}

export function _request({
	url,
	method = "post",
	data = {},
	headers = {},
	isShowLoadig = false,
	isShowError = false,
} = {}) {
	return new Promise((resolve) => {
		if (isShowLoadig) {
			my.showLoading();
		}
		// eslint-disable-next-line no-undef
		const app = getApp();
		my.request({
			url: url.startsWith("http") ? url : joinUrl(host, url),
			method,
			data: Object.assign(data, {
				userId: app.globalData.ywtUserId || "",
				appId: app.globalData.appId || "",
				terminal,
			}),
			headers: {
				"content-type": "application/x-www-form-urlencoded",
				ticket: app.globalData.ticketData.ticket, // todo test
				appId: app.globalData.appId, // todo test
				...headers,
			},
			dataType: "json",
			success(res) {
				const result = res.data || {};
				const code = +result.code;
				if (result && code === 200) {
					resolve([
						null,
						{
							data: result.data,
							code,
						},
					]);
				} else if (code === 20002 || code === 20001 || code === 20008) {
					resolve([
						null,
						{
							code,
							data: null,
						},
					]);
				} else if (code === 500) {
					// 自定义错误
					showErrorMessgage({
						isShowError,
						error: result.message,
					});
					resolve([result, null]);
				} else {
					showErrorMessgage({
						isShowError,
						error: result,
					});
					resolve([result, null]);
				}
			},
			fail(err) {
				showErrorMessgage({
					isShowError,
					error: err,
				});
				resolve([err, null]);
			},
			complete() {
				if (isShowLoadig) {
					my.hideLoading();
				}
			},
		});
	});
}

export function _ywtRequest({
	url,
	method = "post",
	data = {},
	headers = {},
	isShowLoadig = false,
	isShowError = false,
} = {}) {
	return new Promise((resolve) => {
		if (isShowLoadig) {
			my.showLoading();
		}
		const app = getApp();
		my.request({
			url: url.startsWith("http") ? url : joinUrl(ywtRequestUrl, url),
			method,
			data: Object.assign(data, {
				userId: app.globalData.ywtUserId || "",
				appId: app.globalData.appId || "",
				terminal,
			}),
			headers: {
				...headers,
			},
			dataType: "json",
			success(res) {
				const result = res.data || {};
				const code = +result.code;
				if (result && code === 0) {
					resolve([
						null,
						{
							data: result.data,
							code,
						},
					]);
				} else if (code === 20002 || code === 20001 || code === 20008) {
					resolve([
						null,
						{
							code,
							data: null,
						},
					]);
				} else {
					showErrorMessgage({
						isShowError,
						error: result,
					});
					resolve([result, null]);
				}
			},
			fail(err) {
				showErrorMessgage({
					isShowError,
					error: err,
				});
				resolve([err, null]);
			},
			complete() {
				if (isShowLoadig) {
					my.hideLoading();
				}
			},
		});
	});
}

export async function getTicket() {
	// eslint-disable-next-line no-undef
	const app = getApp();
	const { appId } = app.globalData;
	if (!appId) {
		app.globalData.appId = getAppId();
	}
	const [err, res] = await getSilentAuthCode();
	if (err) return [err, null];
	const data = {
		authCode: res.authCode,
		appId: app.globalData.appId,
	};
	const result = await _request({
		url: getTicketUrl,
		data,
	});
	return result;
}

export async function setTicket() {
	const app = getApp();
	const { expiresTime } = app.globalData.ticketData;
	// 如果当前其他请求更新了ticket，则不用重新请求
	if (expiresTime && checkTimeExpire(expiresTime)) {
		return;
	}
	// 如果没有ticket正在请求，则在gloabl上增加setTicket
	if (!app.globalData.getTicketing) {
		app.globalData.setTicket = (async function () {
			app.globalData.getTicketing = true;
			const [err, res] = await getTicket();
			if (err) {
				return [err, null];
			}
			// eslint-disable-next-line no-undef
			app.globalData.ticketData.ticket = res.data.ticket;
			app.globalData.ticketData.expiresTime = res.data.expiresTime;
			app.globalData.getTicketing = false;
			return [null, res];
		})();
	}
	// 如果ticket正在请求，则返回正在请求的ticket
	return app.globalData.setTicket;
}

export default async function request(options) {
	const app = getApp();
	// 如果没有ticket直接请求ticket
	if (!app.globalData.ticketData.ticket && !options.noNeedTicket) {
		await setTicket();
	}
	const [err, res] = await _request(options);
	if (err) return [err, null];
	const code = +getIn(res, ["code"], "");
	if (code === 20001 || code === 20002 || code === 20008) {
		const [error] = await setTicket();
		if (!error) {
			const result = await request(options);
			return result;
		}
		return [error, null];
	}
	const data = res.data || null;
	return [null, data];
}

export async function ywtRequest(options) {
	const [err, res] = await _ywtRequest(options);
	if (err) return [err, null];
	const code = +getIn(res, ["code"], "");
	if (code === 20001 || code === 20002 || code === 20008) {
		const [error] = await setTicket();
		if (!error) {
			const result = await ywtRequest(options);
			return result;
		}
		return [error, null];
	}
	const data = res.data || null;
	return [null, data];
}
