import {CancelToken,Cancel,isCancel} from './cancel.js'
class Request {
	constructor(args) {
		this.defaults = {headers:{'Accept': 'application/json',
			'Content-Type': 'application/x-www-form-urlencoded'},debug:false,...args} || {};
		this.timer = null;
		this.requestTask = null;
		this.aborted = false;
		this.timeoutCancel = false;
		this.Cancel = Cancel;
		this.CancelToken = CancelToken;
		this.isCancel = isCancel;
	}
	interceptors = { // 拦截器
		request: {
			interceptors: [],
			use(fn) {
				this.interceptors.push(fn)		
			},
			async intercept(config) {
				for (let i = 0; i < this.interceptors.length; i++) {
					config = await this.interceptors[i](config)
				}		
				return config
			}
		},
		response: {
			interceptors: [],
			use(fn) {
				this.interceptors.push(fn)
			},
			async intercept(resolve, response) {
				for (let i = 0; i < this.interceptors.length; i++) {
					response = await this.interceptors[i](response)
				}
				return resolve(response)

			}
		}
	}
	abort = () => {
		this.aborted = true;
		this.requestTask ? this.requestTask.abort() : ''
	}

	onerror = async (options={...args}) => {
		let obj = {
			url: options.url,
			method: options.method,
			mes: options.str
		};
		if(options.cancel){
			obj.mes=options.cancel.message || '取消请求'
		}
		if(this.defaults.debug){
			console.log(obj.mes, options)
		}
		return obj;
	}
	request(options) {
		const _this = this;
		let {method, url, data,cancelToken} = options;
		let config = {
			url: this.defaults.baseURL + url,
			method: method.toUpperCase() || 'GET',
			header: this.defaults.headers || {},
			data: data || {},
		}
		return new Proxy(new Promise((resolve, reject) => {
			_this.interceptors.request.intercept(config).then(async (res) => {
				if (_this.aborted) { // 如果请求已被取消,停止执行,返回 reject
					const str = '主动中断请求';
					await _this.onerror({config,str})
					return reject(str)
				}
				if (config.cancelToken) {
				  // Handle cancellation
				  config.cancelToken.promise.then(async function onCanceled(cancel) {
						clearTimeout(_this.timer)
						_this.requestTask = null;
						await _this.onerror({config, cancel})
				    return reject(cancel);
				  });
				}
				_this.requestTask = uni.request({
					...config,
					success: async (res) => {
						clearTimeout(_this.timer) // 清除检测超时定时器
						_this.interceptors.response.intercept(resolve, res) // 执行响应拦截器
					},
					fail: async (error) => {
						console.log(error)
						clearTimeout(_this.timer) // 清除检测超时定时器
						let failTimer = setTimeout(async () => {
							// 区分失败原因为超时或其它原因
							const str = '网络异常或URL无效'
							if (!_this.timeoutCancel) {
								await _this.onerror({config, str})
								clearTimeout(failTimer)
								reject(str)
							}
						}, 300)

					}
				});
				_this.timer = setTimeout(async () => { // 请求超时执行方法
				if (config.cancelToken) {return}
					_this.requestTask.abort(); // 执行取消请求方法
					_this.timeoutCancel = true;
					const str = `网络请求时间超时,当前设置响应时间为${_this.defaults.timeout}`
					await _this.onerror({config, str})
					reject(str)
				}, _this.defaults.timeout || 12345) // 设定检测超时定时器
			})


		}), {
			get: function(target, key, receiver) {
				// console.log(`getting ${key}!`);
				return key === 'abort' ? _this.abort : Reflect.get(target, key, receiver).bind(target); //传入target 为异步函数需要 .bind(target)
			},
			set: function(target, key, value, receiver) {
				// console.log(`setting ${key}!`);
				return Reflect.set(target, key, value, receiver);
			}
		})
	}
}

// class CreateInstance extends Request {
// 	constructor(args) {
// 		super();
// 		super.defaults = args;
// 	}
// }
let unirequest = new Request();
unirequest.create = function(args) {
	return new Request(args)
}

export default unirequest;
