import Request from './request.js';
import errorCode from './errorCode.js';
import {Base64} from "js-base64";
import { getDoctorWxEnv } from '@/config/app-env.js';
import { resolveDoctorWxAuthToken } from '@/utils/doctorWxAuthToken.js';

const { legacyApiBase } = getDoctorWxEnv();

export const config = {
	baseUrl: legacyApiBase
}

const arr = [
	'mobile',
	'call_mobile',
	'express_mobile',
	'doctor',
	'accept_tel',
	'patient_mobile',
	'id_card',
	'idcard',
	'password',
	'phone'
]

// 敏感数据（解密后做脱敏；需与下方 switch 分支一致）
// 注意：call_mobile 只解密不脱敏，供回访拨号使用
const sensitiveData = [
	'id_card',
	'idcard',
	'mobile',
	'express_mobile',
	'patient_mobile',
	'phone'
]
/**
 * 请求拦截器
 * @param {*} options
 */
const reqInterceptor = async (options) => {
	// 加密
	if (options.data != null && options.type !== 'upload') {
		options.data = getRes(options.data, false)
	}
	options.header = {
		...options.header
	}
	const skipToken = options.header.isToken === false
	const isClinicAdminReq = options.header._clinicAdmin === '1'
		|| (options.url && String(options.url).indexOf('clinic-admin') !== -1)
	const isPlatformAdminReq = options.header._platformAdmin === '1'
		|| (options.url && String(options.url).indexOf('platform-admin') !== -1)
	const isSalespersonReq = options.header._salesperson === '1'
		|| (options.url && String(options.url).indexOf('salesperson-') !== -1)
	const isClinicSalespersonReq = options.header._clinicSalesperson === '1'
		|| (options.url && String(options.url).indexOf('clinic-salesperson-') !== -1)
	const isDoctorWxAuthReq = options.url && String(options.url).indexOf('doctor-wx-auth') !== -1
	// 内部控制位，不得作为 HTTP 头发出
	delete options.header.isToken
	delete options.header._clinicAdmin
	delete options.header._platformAdmin
	delete options.header._salesperson
	delete options.header._clinicSalesperson
	const clinicToken = uni.getStorageSync('clinic_admin_token')
	const platformToken = uni.getStorageSync('platform_admin_token')
	const salespersonToken = uni.getStorageSync('salesperson_token')
	const clinicSalespersonToken = uni.getStorageSync('clinic_salesperson_token')
	const doctorToken = uni.getStorageSync('token')
	const loginMode = uni.getStorageSync('loginMode')
	if (!skipToken) {
		if (isDoctorWxAuthReq) {
			const authToken = resolveDoctorWxAuthToken()
			if (authToken) {
				options.header['authorization'] = `Bearer ${authToken}`
			}
		} else if (isPlatformAdminReq && platformToken) {
			options.header['authorization'] = `Bearer ${platformToken}`
		} else if (isSalespersonReq && salespersonToken) {
			options.header['authorization'] = `Bearer ${salespersonToken}`
		} else if (isClinicSalespersonReq && clinicSalespersonToken) {
			options.header['authorization'] = `Bearer ${clinicSalespersonToken}`
		} else if (isClinicAdminReq && clinicToken) {
			options.header['authorization'] = `Bearer ${clinicToken}`
		} else if (doctorToken) {
			options.header['authorization'] = `Bearer ${doctorToken}`
		}
	}
	return options;
}

/**
 * 响应拦截器
 */
const resInterceptor = (response, conf = {}) => {
	// 网络状态码
	const statusCode = response.statusCode|| response.errcode;
	// 响应拦截器
	if (statusCode >= 200 && statusCode < 300) {
		_responseLog(response, conf, "response 200-299")
		// 解密（Yii：业务在 data；Laravel jok：业务在 result）
		let res = response.data
		if (res == null || typeof res !== 'object') {
			return res
		}
		if (res.data != null) {
			res.data = getRes(res.data)
		}
		if (res.result != null) {
			res.result = getRes(res.result)
		}
		return res
	} else if (statusCode === 500) {
		uni.showToast({
			icon: 'error',
			title: response['msg'] || errorCode[statusCode]
		})
		_responseLog(response, conf, "response 500")
		// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
		return {
			// 根据当前字段来判断是否reject
			wakaryReqToReject: true,
			// 下面可以配置其他返回信息，方便统一处理reject
			// 以下内容作为reject的返回，根据需求处理，返回具体错误信息
			msg: "服务器错误",
			res: response
		}
	} else if (statusCode === 401) {
		uni.showToast({
			icon: 'error',
			title: response['msg'] || response['message'] || errorCode[statusCode]
		})
		const loginMode = uni.getStorageSync('loginMode')
		if (loginMode === 'platform_admin') {
			uni.removeStorageSync('platform_admin_token')
			uni.removeStorageSync('platform_admin_user')
			uni.removeStorageSync('loginMode')
		} else if (loginMode === 'salesperson') {
			uni.removeStorageSync('salesperson_token')
			uni.removeStorageSync('salesperson_user')
			uni.removeStorageSync('loginMode')
		} else if (loginMode === 'clinic_salesperson') {
			uni.removeStorageSync('clinic_salesperson_token')
			uni.removeStorageSync('clinic_salesperson_user')
			uni.removeStorageSync('loginMode')
		} else if (loginMode === 'clinic_admin') {
			uni.removeStorageSync('clinic_admin_token')
			uni.removeStorageSync('clinic_admin_user')
			uni.removeStorageSync('loginMode')
		} else {
			uni.removeStorageSync('token')
			uni.removeStorageSync('loginInfo')
			uni.removeStorageSync('identity')
		}
		setTimeout(() => {
			uni.reLaunch({ url: '/pages/login/index' })
		}, 1000)
		_responseLog(response, conf, "response 401")
		// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
		return {
			// 根据当前字段来判断是否reject
			wakaryReqToReject: true,
			// 下面可以配置其他返回信息，方便统一处理reject
			// 以下内容作为reject的返回，根据需求处理，返回具体错误信息
			msg: response['msg'] || errorCode[statusCode],
			res: response
		}
	} else {
		uni.showToast({
			icon: 'error',
			title: response['msg'] || errorCode[statusCode]
		})
		_responseLog(response, conf, "response 300-499");
		// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
		return {
			// 根据当前字段来判断是否reject
			wakaryReqToReject: true,
			// 下面可以配置其他返回信息，方便统一处理reject
			// 以下内容作为reject的返回，根据需求处理，返回具体错误信息
			msg: "response 300-499",
			res: response
		}
	}
}

/**
 * request log
 */
function _requestLog(req, describe = null) {
	if (process.env.NODE_ENV === 'development') {}
}

/**
 * response log
 */
function _responseLog(res, conf = {}, describe = null) {
	let _statusCode = res.statusCode;
	if (process.env.NODE_ENV === 'development') {}

	if (_statusCode === 500) {
		// save log to server
	}
}

function getRes(obj, isDecode = true) {
	if (obj == null || typeof obj !== 'object') {
		return obj
	}
	try {
		for (const key in obj) {
			if (Array.isArray(obj[key])) {
				obj[key] = getRes(obj[key])
			} else if (typeof obj[key] === 'object' && obj[key] !== null) {
				obj[key] = getRes(obj[key])
			} else {
				// 判断obj[key]是否在arr中
				if (arr.indexOf(key) !== -1) {
					if (obj[key] == null || obj[key] === '') continue
					let aseFile = ''
					if (isDecode === true) {
						aseFile = customBase64Decode(obj[key])
					} else {
						aseFile = customBase64Encode(obj[key])
					}
					const isGarbled = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\xFF]|[\u{E000}-\u{F8FF}]/u.test(
						typeof aseFile === 'string' ? aseFile : ''
					)
					if (isGarbled) {
						aseFile = obj[key]
					}
					if (isDecode === true) {
						if (sensitiveData.indexOf(key) !== -1) {
							// 数据脱敏，自动匹配姓名、手机号、身份证
							switch (key) {
								case 'express_name':
								case 'express_region':
								case 'accept_name':
								case 'patient':
									// 保留前两个字符，其余用星号代替
									aseFile = aseFile.slice(0, 1).padEnd(aseFile.length, '*');
									break;
								case 'mobile':
								case 'express_mobile':
								case 'phone':
									// 保留前三位和后四位，中间用星号代替
									aseFile = aseFile.slice(0, 3).padEnd(aseFile.length - 4, '*') + aseFile.slice(-4);
									break;
								case 'id_card':
								case 'idcard':
									// 保留前六位和后四位，中间用星号代替
									aseFile = aseFile.slice(0, 6).padEnd(aseFile.length - 4, '*') + aseFile.slice(-4);
									break;
								default:
									// 默认情况下，全部用星号代替
									break;
							}
						}
					}
					obj[key] = aseFile
				}
			}
		}
		return obj
	} catch (error) {
		console.error('错误', error)
		return obj
	}
}

function customBase64Decode(data) {
	if (data == null || data === '') return data
	// return data
	try {
		// 第一次Base64解码
		const decodedFirst = Base64.decode(data)
		// 截取从第30个字符开始往后的内容
		const subStr = decodedFirst.slice(30)
		// 第二次Base64解码
		return Base64.decode(subStr) != ''? Base64.decode(subStr): data
	} catch (error) {
		console.error(`解码Base64字符串【${data}】时发生错误`, error)
		return data
	}
}

// 加密
function customBase64Encode(data) {
	if (data == null || data === '') return data
	// return data
	try {
		// 和加密方法差不多但是是要生成30个随机字符
		let randomString = ''
		for (let i = 0; i < 30; i++) {
			const randomChar = String.fromCharCode(Math.floor(Math.random() * (126 - 32 + 1)) + 32)
			randomString += randomChar
		}
		const encoded = Base64.encode(data)
		return Base64.encode(randomString + encoded)
	} catch (error) {
		console.error(`加密字符串【${data}】时发生错误`, error)
		return data
	}
}


/**
 * 请求方法封装
 */

export  const req = new Request(config, reqInterceptor, resInterceptor)
