import { getApiBaseUrl, isApiConfigured } from '../config/api.uts'
import { clearSession, getAccessToken, getCurrentStoreId } from './session.uts'
import { refreshMerchantSession } from './session-refresh.uts'

export type HttpError = {
	code: string
	message: string
	statusCode: number
	traceId: string
}

export type HttpRequestOptions = {
	path: string
	method?: string
	data?: any
	idempotencyKey?: string
	skipAuth?: boolean
	skipStoreContext?: boolean
	skipUnauthorizedRedirect?: boolean
	retriedAfterRefresh?: boolean
	header?: any
}

const requestTimeout = 15000
let unauthorizedRedirecting = false

const createRequestId = (): string => 'merchant-' + Date.now() + '-' + Math.floor(Math.random() * 1000000)

const buildUrl = (path: string): string => {
	if (path.indexOf('http://') == 0 || path.indexOf('https://') == 0) return path
	return getApiBaseUrl().replace(/\/$/, '') + '/' + path.replace(/^\//, '')
}

const unavailable = (): HttpError => ({
	code: 'API_NOT_CONFIGURED',
	message: '后台服务尚未配置，请联系管理员',
	statusCode: 0,
	traceId: ''
})

// 登录请求（skipAuth）的 401 是账号密码校验失败，要展示后端给的失败原因；
// 其余请求的 401 才是会话失效。
const unauthorizedMessage = (skipAuth: boolean | null, payload: any): string => {
	if (skipAuth == true && payload != null && payload.message != null && ('' + payload.message).length > 0) {
		return '' + payload.message
	}
	return '登录已失效，请重新登录'
}

const redirectToLogin = () => {
	if (unauthorizedRedirecting) return
	unauthorizedRedirecting = true
	uni.reLaunch({
		url: '/pages/login/login',
		complete: () => {
			setTimeout(() => {
				unauthorizedRedirecting = false
			}, 500)
		}
	})
}

export const request = <T>(
	options: HttpRequestOptions,
	onSuccess: (data: T, traceId: string) => void,
	onError: (error: HttpError) => void
): (() => void) => {
	if (!isApiConfigured() || options.path.trim().length == 0) {
		onError(unavailable())
		return () => {}
	}

	const headers: any = {
		'Content-Type': 'application/json',
		'X-Request-Id': createRequestId(),
		'X-Client-Platform': 'mp-weixin',
		'X-Client-Version': '1.0.0'
	}
	if (options.header != null) {
		const customHeader = options.header as any
		Object.keys(customHeader).forEach((key: string) => {
			headers[key] = customHeader[key]
		})
	}
	if (!options.skipAuth) {
		const token = getAccessToken()
		if (token.length > 0) headers['Authorization'] = 'Bearer ' + token
	}
	if (!options.skipStoreContext) {
		const storeId = getCurrentStoreId()
		if (storeId.length > 0) headers['X-Merchant-Store-Id'] = storeId
	}
	if (options.idempotencyKey != null && options.idempotencyKey.length > 0) {
		headers['X-Idempotency-Key'] = options.idempotencyKey
	}

	let cancelled = false
	const task: any = uni.request({
		url: buildUrl(options.path),
		method: options.method != null ? options.method : 'GET',
		data: options.data,
		header: headers,
		timeout: requestTimeout,
		success: (response: any) => {
			const payload: any = response.data
			const traceId = payload != null && payload.traceId != null ? payload.traceId as string : ''
			const statusCode = response.statusCode as number
			if (statusCode == 401) {
				if (!options.skipAuth && !options.retriedAfterRefresh) {
					refreshMerchantSession((refreshed: boolean) => {
						if (refreshed) {
							const retryOptions: HttpRequestOptions = {
								path: options.path,
								method: options.method,
								data: options.data,
								idempotencyKey: options.idempotencyKey,
								skipAuth: options.skipAuth,
								skipStoreContext: options.skipStoreContext,
								skipUnauthorizedRedirect: options.skipUnauthorizedRedirect,
								header: options.header,
								retriedAfterRefresh: true
							}
							request<T>(retryOptions, onSuccess, onError)
							return
						}
						const error: HttpError = { code: 'UNAUTHORIZED', message: '登录已失效，请重新登录', statusCode: 401, traceId: traceId }
						onError(error)
						if (!options.skipUnauthorizedRedirect) redirectToLogin()
					})
					return
				}
				clearSession()
				const error: HttpError = { code: 'UNAUTHORIZED', message: unauthorizedMessage(options.skipAuth, payload), statusCode: 401, traceId: traceId }
				onError(error)
				if (!options.skipUnauthorizedRedirect) redirectToLogin()
				return
			}
			if (statusCode < 200 || statusCode >= 300) {
				onError({
					code: 'HTTP_' + statusCode,
					message: payload != null && payload.message != null ? payload.message as string : '服务暂不可用，请稍后重试',
					statusCode: statusCode,
					traceId: traceId
				})
				return
			}
			const businessCode = payload != null && payload.code != null ? '' + payload.code : '0'
			if (businessCode != '0' && businessCode != '200' && businessCode.toLowerCase() != 'success') {
				onError({
					code: businessCode,
					message: payload != null && payload.message != null ? payload.message as string : '业务处理失败',
					statusCode: statusCode,
					traceId: traceId
				})
				return
			}
			onSuccess((payload != null && payload.data != null ? payload.data : payload) as T, traceId)
		},
		fail: (error: any) => {
			if (cancelled) return
			onError({
				code: 'NETWORK_ERROR',
				message: error != null && error.errMsg != null ? error.errMsg as string : '网络连接失败，请稍后重试',
				statusCode: 0,
				traceId: ''
			})
		}
	})

	return () => {
		cancelled = true
		task.abort()
	}
}
