import { pages, subPackages, tabBar } from '@/pages.json'
import { isMpWeixin } from './platform'
import { useAppStore } from '@/store'

const getLastPage = () => {
	// getCurrentPages() 至少有1个元素，所以不再额外判断
	// const lastPage = getCurrentPages().at(-1)
	// 上面那个在低版本安卓中打包回报错，所以改用下面这个【虽然我加了src/interceptions/prototype.ts，但依然报错】
	const pages = getCurrentPages()
	return pages[pages.length - 1]
}

/** 判断当前页面是否是tabbar页  */
export const getIsTabbar = () => {
	if (!tabBar) {
		return false
	}
	if (!tabBar.list.length) {
		// 通常有tabBar的话，list不能有空，且至少有2个元素，这里其实不用处理
		return false
	}
	const lastPage = getLastPage()
	const currPath = lastPage.route
	return !!tabBar.list.find((e) => e.pagePath === currPath)
}

/**
 * 获取当前页面路由的 path 路径和 redirectPath 路径
 * path 如 ‘/pages/login/index’
 * redirectPath 如 ‘/pages/demo/base/route-interceptor’
 */
export const currRoute = () => {
	const lastPage = getLastPage()
	const currRoute = (lastPage as any).$page
	// 经过多端测试，只有 fullPath 靠谱，其他都不靠谱
	const { fullPath } = currRoute as { fullPath : string }
	// eg: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor (小程序)
	// eg: /pages/login/index?redirect=%2Fpages%2Froute-interceptor%2Findex%3Fname%3Dfeige%26age%3D30(h5)
	return getUrlObj(fullPath)
}

const ensureDecodeURIComponent = (url : string) => {
	if (url.startsWith('%')) {
		return ensureDecodeURIComponent(decodeURIComponent(url))
	}
	return url
}
/**
 * 解析 url 得到 path 和 query
 * 比如输入url: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor
 * 输出: {path: /pages/login/index, query: {redirect: /pages/demo/base/route-interceptor}}
 */
export const getUrlObj = (url : string) => {
	const [path, queryStr] = url.split('?')

	if (!queryStr) {
		return {
			path,
			query: {},
		}
	}
	const query : Record<string, string> = {}
	queryStr.split('&').forEach((item) => {
		const [key, value] = item.split('=')
		query[key] = ensureDecodeURIComponent(value) // 这里需要统一 decodeURIComponent 一下，可以兼容h5和微信y
	})
	return { path, query }
}
/**
 * 得到所有的需要登录的pages，包括主包和分包的
 * 这里设计得通用一点，可以传递key作为判断依据，默认是 needLogin, 与 route-block 配对使用
 * 如果没有传 key，则表示所有的pages，如果传递了 key, 则表示通过 key 过滤
 */
export const getAllPages = (key = 'needLogin') => {
	// 这里处理主包
	const mainPages = [
		...pages
			.filter((page) => !key || page[key])
			.map((page) => ({
				...page,
				path: `/${page.path}`,
			})),
	]
	// 这里处理分包
	const subPages : any[] = []
	subPackages.forEach((subPageObj) => {
		const { root } = subPageObj

		subPageObj.pages
			.filter((page) => !key || page[key])
			.forEach((page : { path : string } & Record<string, any>) => {
				subPages.push({
					...page,
					path: `/${root}/${page.path}`,
				})
			})
	})
	const result = [...mainPages, ...subPages]
	return result
}

/**
 * 得到所有的需要登录的pages，包括主包和分包的
 * 只得到 path 数组
 */
export const getNeedLoginPages = () : string[] => getAllPages('needLogin').map((page) => page.path)

/**
 * 得到所有的需要登录的pages，包括主包和分包的
 * 只得到 path 数组
 */
export const needLoginPages : string[] = getAllPages('needLogin').map((page) => page.path)

/**
 * 根据微信小程序当前环境，判断应该获取的BaseUrl
 */
export const getEnvBaseUrl = () => {
	// 请求基准地址
	let baseUrl = import.meta.env.VITE_SERVER_BASEURL

	// 微信小程序端环境区分
	if (isMpWeixin) {
		const {
			miniProgram: { envVersion },
		} = uni.getAccountInfoSync()

		switch (envVersion) {
			case 'develop':
				baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_DEVELOP || baseUrl
				break
			case 'trial':
				baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_TRIAL || baseUrl
				break
			case 'release':
				baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_RELEASE || baseUrl
				break
		}
	}

	return baseUrl
}

/**
 * 根据微信小程序当前环境，判断应该获取的UPLOAD_BASEURL
 */
export const getEnvBaseUploadUrl = () => {
	// 请求基准地址
	let baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL

	// 微信小程序端环境区分
	if (isMpWeixin) {
		const {
			miniProgram: { envVersion },
		} = uni.getAccountInfoSync()

		switch (envVersion) {
			case 'develop':
				baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_DEVELOP || baseUploadUrl
				break
			case 'trial':
				baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_TRIAL || baseUploadUrl
				break
			case 'release':
				baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_RELEASE || baseUploadUrl
				break
		}
	}

	return baseUploadUrl
}
/**
 * 时间格式化
 * @param value
 * @param fmt
 * @returns {*}
 */
export function formatDate(value, fmt) {
	var regPos = /^\d+(\.\d+)?$/;
	if (regPos.test(value)) {
		//如果是数字
		let getDate = new Date(value);
		let o = {
			'M+': getDate.getMonth() + 1,
			'd+': getDate.getDate(),
			'h+': getDate.getHours(),
			'H+': getDate.getHours(),
			'm+': getDate.getMinutes(),
			's+': getDate.getSeconds(),
			'q+': Math.floor((getDate.getMonth() + 3) / 3),
			'S': getDate.getMilliseconds()
		};
		if (/(y+)/.test(fmt)) {
			fmt = fmt.replace(RegExp.$1, (getDate.getFullYear() + '').substr(4 - RegExp.$1.length))
		}
		for (let k in o) {
			if (new RegExp('(' + k + ')').test(fmt)) {
				fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
			}
		}
		return fmt;
	} else {
		//TODO
		if (value && value.length > 0) {
			value = value.trim();
			return value.substr(0, fmt.length);
		}
		return value
	}
}

/**
 * 判断是否有新版本
 * @param version 接口返回的版本号
 * @param isWgt 是否是热资源更新 默认不是
 */
export const hasNewVersion = (version, isWgt = false) => {
	// #ifdef APP_PLUS
	return new Promise((resolve) => {
		const transfer = (str) => str.replace(/\./g, '')
		if (isWgt) {
			plus.runtime.getProperty(plus.runtime.appid, (widgetInfo) => {
				const currentVersion = widgetInfo.version
				resolve(+transfer(version) > +transfer(currentVersion))
			})
		} else {
			const currentVersion = plus.runtime.version
			resolve(+transfer(version) > +transfer(currentVersion))
		}
	})
	// #endif
}

export function onClickUpdate(updateType : string, url) {
	// #ifdef APP-PLUS
	if (updateType != 'wgt') plus.runtime.openURL(url.apkUrl)
	else downloadApp(url.wgtUrl)
	// #endif
}

function downloadApp(url : string) {
	var dtask = plus.downloader.createDownload(url, {
		filename: `_downloads/wgt-${Date.now()}.wgt` //利用保存路径，实现下载文件的重命名
	}, function (d, status) {
		//d为下载的文件对象
		if (status == 200) {
			//下载成功,d.filename是文件在保存在本地的相对路径，使用下面的API可转为平台绝对路径
			var fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename);
			installApp(fileSaveUrl)
		} else {
			//下载失败
			plus.downloader.clear(); //清除下载任务
			uni.showToast({
				title: 'App下载失败！',
				icon: 'error'
			})
		}
	})
	let prg = 0
	let showLoading = plus.nativeUI.showWaiting('正在下載')
	dtask.start()
	dtask.addEventListener('statechanged', (task) => {
		// 给下载任务设置一个监听 并根据状态  做操作
		switch (task.state) {
			case 1:
				showLoading.setTitle("正在下载")
				break
			case 2:
				showLoading.setTitle("已连接到服务器")
				break
			case 3: {
				const downloaded = +task.downloadedSize; // 转为数字
				const total = +task.totalSize; // 转为数字
				prg = total > 0 ? Math.floor((downloaded / total) * 100) : 0;
				showLoading.setTitle(`正在下载 ${prg}%`);
				break;
			}
			case 4:
				plus.nativeUI.closeWaiting()
				//下载完成
				break
		}
	})
}

function installApp(tempFilePath : string) {
	// #ifdef APP-PLUS
	plus.runtime.install(
		tempFilePath, {
		force: true
	},
		() => {
			uni.showModal({
				title: '更新',
				content: '更新成功，请点击确认后重启',
				showCancel: false,
				success(res) {
					if (res.confirm) {
						plus.runtime.restart()
					}
				}
			})
		},
		() =>
			uni.showToast({
				title: '安装失败！',
				icon: 'error'
			})
	)
	// #endif
}

/**
 * 定位
 */
export const getLocation = () => {
	const store = useAppStore()
	// 先尝试获取位置，失败时再回退
	uni.getLocation({
		type: 'wgs84',
		success: function (position) {
			// 成功获取位置后请求地理编码
			uni.request({
				url: 'http://api.tianditu.gov.cn/geocoder',
				method: 'GET',
				data: {
					postStr: JSON.stringify({
						lon: position.longitude,
						lat: position.latitude,
						ver: 1
					}),
					type: 'geocode',
					tk: '30fe0f0c1b2320e112bde797f3ddaff4'
				},
				success: function (res : any) {
					let data = res.data;
					if (data.status == 0) {
						const obj = data.result.addressComponent
						store.setPosition(obj.city ? obj.city : obj.province) //市
						store.setLocation(obj.city ? obj.province + obj.city + obj.county : obj.province + obj.county) //省市区
						getWeather(position.latitude, position.longitude)
					} else {
						handleDefaultLocation()
					}
				},
				fail: function (err) {
					uni.showToast({
						title: '位置解析失败',
						icon: 'error'
					})
					handleDefaultLocation()
				}
			});
		},
		fail: function (err) {
			// 根据不同错误码处理
			if (err.errCode === 2 || err.errCode === 12) {
				// 2: 位置服务不可用, 12: 定位权限未开启
				uni.showToast({
					title: '请开启定位服务',
					icon: 'error'
				})

			} else {
				uni.showToast({
					title: '定位获取失败',
					icon: 'error'
				})
			}
			handleDefaultLocation()
		}
	});
}

const getWeather = (lat : string, lon : string) => {
	let params = {
		lat: lat,
		lon: lon
	}
	weatherRequest(params)
}

// 处理默认位置和天气
function handleDefaultLocation() {
	useAppStore().setPosition('濮阳市')
	weatherRequest({
		q: '濮阳市'
	})
}


function weatherRequest(params: { lat?: string; lon?: string; q?: string }) {
	const store = useAppStore()
	uni.request({
		url: 'https://api.openweathermap.org/data/2.5/weather',
		method: 'GET',
		data: {
			...params,
			appid: '600a60694b0e453dfbaafa862f1d1482',
			lang: 'zh_cn'
		},
		success: function (res : any) {
			if (res.data && res.data.main && res.data.weather) {
				store.setTemperature(
					Math.round(res.data.main.temp - 273.15)
				)
				store.setWeather(
					res.data.weather[0].icon
				)
			} else {
				uni.showToast({
					title: '天气数据格式错误',
					icon: 'error'
				})
			}
		},
		fail: function () {
			uni.showToast({
				title: '天气获取失败',
				icon: 'error'
			})
		}
	});
}