import type { PopsAlertDetails } from "../components/alert/indexType";
import type { PopsConfirmDetails } from "../components/confirm/indexType";
import type { PopsDrawerDetails } from "../components/drawer/indexType";
import type { PopsFolderDetails } from "../components/folder/indexType";
import type { PopsIframeDetails } from "../components/iframe/indexType";
import type { PopsLoadingDetails } from "../components/loading/indexType";
import type { PopsPanelDetails } from "../components/panel/indexType";
import type { PopsPromptDetails } from "../components/prompt/indexType";
import type { PopsLayerCommonConfig } from "../types/layer";
import type { PopsLayerMode } from "../types/main";
import { popsDOMUtils } from "./PopsDOMUtils";
import { popsUtils } from "./PopsUtils";
import { PopsCore } from "../Core";
import { pops } from "../Pops";

export const PopsInstanceUtils = {
	/**
	 * 获取页面中最大的z-index的元素信息
	 * @param deviation 获取最大的z-index值的偏移，默认是+1
	 * @param node 进行判断的元素，默认是document
	 * @param ignoreCallBack 执行元素处理时调用的函数，返回false可忽略不想要处理的元素
	 * @example
	 * Utils.getMaxZIndexNodeInfo();
	 * > {
	 *   node: ...,
	 *   zIndex: 1001
	 * }
	 **/
	getMaxZIndexNodeInfo(
		deviation = 1,
		target: Element | ShadowRoot | Document = PopsCore.document,
		ignoreCallBack?: (
			$ele: Element | HTMLElement | ShadowRoot
		) => boolean | void
	): {
		node: Element;
		zIndex: number;
	} {
		deviation = Number.isNaN(deviation) ? 1 : deviation;
		// 最大值 2147483647
		// const maxZIndex = Math.pow(2, 31) - 1;
		// 比较值 2000000000
		const maxZIndexCompare = 2 * Math.pow(10, 9);
		// 当前页面最大的z-index
		let zIndex = 0;
		// 当前的最大z-index的元素，调试使用
		// @ts-ignore
		let maxZIndexNode: Element = null;
		/**
		 * 元素是否可见
		 * @param $css
		 */
		function isVisibleNode($css: CSSStyleDeclaration): boolean {
			return $css.position !== "static" && $css.display !== "none";
		}
		/**
		 * 查询元素的z-index
		 * 并比较值是否是已获取的最大值
		 * @param $ele
		 */
		function queryMaxZIndex($ele: Element) {
			if (typeof ignoreCallBack === "function") {
				let ignoreResult = ignoreCallBack($ele);
				if (typeof ignoreResult === "boolean" && !ignoreResult) {
					return;
				}
			}
			/** 元素的样式 */
			const nodeStyle = PopsCore.window.getComputedStyle($ele);
			/* 不对position为static和display为none的元素进行获取它们的z-index */
			if (isVisibleNode(nodeStyle)) {
				let nodeZIndex = parseInt(nodeStyle.zIndex);
				if (!isNaN(nodeZIndex)) {
					if (nodeZIndex > zIndex) {
						// 赋值到全局
						zIndex = nodeZIndex;
						maxZIndexNode = $ele;
					}
				}
				// 判断shadowRoot
				if ($ele.shadowRoot != null && $ele instanceof ShadowRoot) {
					$ele.shadowRoot.querySelectorAll("*").forEach(($shadowEle) => {
						queryMaxZIndex($shadowEle);
					});
				}
			}
		}
		target.querySelectorAll("*").forEach(($ele, index) => {
			queryMaxZIndex($ele);
		});
		zIndex += deviation;
		if (zIndex >= maxZIndexCompare) {
			// 最好不要超过最大值
			zIndex = maxZIndexCompare;
		}
		return {
			node: maxZIndexNode,
			zIndex: zIndex,
		};
	},
	/**
	 * 获取pops所有弹窗中的最大的z-index
	 * @param deviation
	 */
	getPopsMaxZIndex(deviation: number = 1) {
		deviation = Number.isNaN(deviation) ? 1 : deviation;
		// 最大值 2147483647
		// const browserMaxZIndex = Math.pow(2, 31) - 1;
		// 比较值 2000000000
		const maxZIndex = 2 * Math.pow(10, 9);
		// 当前页面最大的z-index
		let zIndex = 0;
		// 当前的最大z-index的元素，调试使用
		let maxZIndexNode = null as HTMLDivElement | null;

		/**
		 * 元素是否可见
		 * @param $css
		 */
		function isVisibleNode($css: CSSStyleDeclaration): boolean {
			return $css.position !== "static" && $css.display !== "none";
		}
		Object.keys(pops.config.layer).forEach((layerName) => {
			let layerList = pops.config.layer[layerName as PopsLayerMode];
			for (let index = 0; index < layerList.length; index++) {
				const layer = layerList[index];
				let nodeStyle = window.getComputedStyle(layer.animElement);
				/* 不对position为static和display为none的元素进行获取它们的z-index */
				if (isVisibleNode(nodeStyle)) {
					let nodeZIndex = parseInt(nodeStyle.zIndex);
					if (!isNaN(nodeZIndex)) {
						if (nodeZIndex > zIndex) {
							zIndex = nodeZIndex;
							maxZIndexNode = layer.animElement;
						}
					}
				}
			}
		});
		zIndex += deviation;
		let isOverMaxZIndex = zIndex >= maxZIndex;
		if (isOverMaxZIndex) {
			// 超出z-index最大值
			zIndex = maxZIndex;
		}
		return { zIndex: zIndex, animElement: maxZIndexNode, isOverMaxZIndex };
	},
	/**
	 * 获取页面中最大的z-index
	 * @param deviation 获取最大的z-index值的偏移，默认是+1
	 * @example
	 * getMaxZIndex();
	 * > 1001
	 **/
	getMaxZIndex(deviation = 1): number {
		return this.getMaxZIndexNodeInfo(deviation).zIndex;
	},
	/**
	 * 获取CSS Rule
	 * @param sheet
	 * @returns
	 */
	getKeyFrames(sheet: CSSStyleSheet) {
		let result = {};
		Object.keys(sheet.cssRules).forEach((key) => {
			if (
				(sheet.cssRules as any)[key].type === 7 &&
				(sheet.cssRules as any)[key].name.startsWith("pops-anim-")
			) {
				(result as any)[(sheet.cssRules as any)[key].name] = (
					sheet.cssRules as any
				)[key];
			}
		});
		return result;
	},
	/**
	 * 删除配置中对应的对象
	 * @param moreLayerConfigList 配置实例列表
	 * @param  guid 唯一标识
	 * @param isAll 是否全部删除
	 */
	removeInstance(
		moreLayerConfigList: PopsLayerCommonConfig[][],
		guid: string,
		isAll = false
	) {
		/**
		 * 移除元素实例
		 * @param layerCommonConfig
		 */
		function removeItem(layerCommonConfig: PopsLayerCommonConfig) {
			if (typeof layerCommonConfig.beforeRemoveCallBack === "function") {
				// 调用移除签的回调
				layerCommonConfig.beforeRemoveCallBack(layerCommonConfig);
			}
			layerCommonConfig?.animElement?.remove();
			layerCommonConfig?.popsElement?.remove();
			layerCommonConfig?.maskElement?.remove();
			layerCommonConfig?.$shadowContainer?.remove();
		}
		// [ layer[], layer[],...]
		moreLayerConfigList.forEach((layerConfigList) => {
			//  layer[]
			layerConfigList.forEach((layerConfigItem, index) => {
				// 移除全部或者guid相同
				if (isAll || layerConfigItem["guid"] === guid) {
					// 判断是否有动画
					if (
						pops.config.animation.hasOwnProperty(
							layerConfigItem.animElement.getAttribute("anim") as string
						)
					) {
						layerConfigItem.animElement.style.width = "100%";
						layerConfigItem.animElement.style.height = "100%";
						(layerConfigItem.animElement.style as any)["animation-name"] =
							layerConfigItem.animElement.getAttribute("anim") + "-reverse";
						if (
							pops.config.animation.hasOwnProperty(
								(layerConfigItem.animElement.style as any)["animation-name"]
							)
						) {
							popsDOMUtils.on(
								layerConfigItem.animElement,
								popsDOMUtils.getAnimationEndNameList(),
								function () {
									removeItem(layerConfigItem);
								},
								{
									capture: true,
								}
							);
						} else {
							removeItem(layerConfigItem);
						}
					} else {
						removeItem(layerConfigItem);
					}
					layerConfigList.splice(index, 1);
				}
			});
		});

		return moreLayerConfigList;
	},
	/**
	 * 隐藏
	 * @param popsType
	 * @param layerConfigList
	 * @param guid
	 * @param config
	 * @param animElement
	 * @param maskElement
	 */
	hide(
		popsType: PopsLayerMode,
		layerConfigList: PopsLayerCommonConfig[],
		guid: string,
		config:
			| PopsAlertDetails
			| PopsDrawerDetails
			| PopsPromptDetails
			| PopsConfirmDetails
			| PopsIframeDetails
			| PopsLoadingDetails
			| PopsPanelDetails
			| PopsFolderDetails,
		animElement: HTMLElement,
		maskElement: HTMLElement
	) {
		let popsElement =
			animElement.querySelector<HTMLDivElement>(".pops[type-value]")!;
		if (popsType === "drawer") {
			let drawerConfig = config as Required<PopsDrawerDetails>;
			setTimeout(() => {
				maskElement.style.setProperty("display", "none");
				if (["top", "bottom"].includes(drawerConfig.direction)) {
					popsElement.style.setProperty("height", "0");
				} else if (["left", "right"].includes(drawerConfig.direction)) {
					popsElement.style.setProperty("width", "0");
				} else {
					console.error("未知direction：", drawerConfig.direction);
				}
			}, drawerConfig.closeDelay);
		} else {
			layerConfigList.forEach((layerConfigItem) => {
				if (layerConfigItem.guid === guid) {
					/* 存在动画 */
					layerConfigItem.animElement.style.width = "100%";
					layerConfigItem.animElement.style.height = "100%";
					(layerConfigItem.animElement.style as any)["animation-name"] =
						layerConfigItem.animElement.getAttribute("anim") + "-reverse";
					if (
						pops.config.animation.hasOwnProperty(
							(layerConfigItem.animElement.style as any)["animation-name"]
						)
					) {
						function animationendCallBack() {
							layerConfigItem.animElement.style.display = "none";
							if (layerConfigItem.maskElement) {
								layerConfigItem.maskElement.style.display = "none";
							}
							popsDOMUtils.off(
								layerConfigItem.animElement,
								popsDOMUtils.getAnimationEndNameList(),
								animationendCallBack,
								{
									capture: true,
								}
							);
						}
						popsDOMUtils.on(
							layerConfigItem.animElement,
							popsDOMUtils.getAnimationEndNameList(),
							animationendCallBack,
							{
								capture: true,
							}
						);
					} else {
						layerConfigItem.animElement.style.display = "none";
						if (layerConfigItem.maskElement) {
							layerConfigItem.maskElement.style.display = "none";
						}
					}

					return;
				}
			});
		}
	},

	/**
	 * 显示
	 * @param popsType
	 * @param layerConfigList
	 * @param guid
	 * @param config
	 * @param animElement
	 * @param maskElement
	 */
	show(
		popsType: PopsLayerMode,
		layerConfigList: PopsLayerCommonConfig[],
		guid: string,
		config:
			| PopsAlertDetails
			| PopsDrawerDetails
			| PopsPromptDetails
			| PopsConfirmDetails
			| PopsIframeDetails
			| PopsLoadingDetails
			| PopsPanelDetails
			| PopsFolderDetails,
		animElement: HTMLElement,
		maskElement: HTMLElement
	) {
		let popsElement =
			animElement.querySelector<HTMLDivElement>(".pops[type-value]")!;
		if (popsType === "drawer") {
			let drawerConfig = config as PopsDrawerDetails;
			setTimeout(() => {
				maskElement.style.setProperty("display", "");
				let direction = drawerConfig.direction!;
				let size = drawerConfig.size!.toString();
				if (["top", "bottom"].includes(direction)) {
					popsElement.style.setProperty("height", size);
				} else if (["left", "right"].includes(direction)) {
					popsElement.style.setProperty("width", size);
				} else {
					console.error("未知direction：", direction);
				}
			}, drawerConfig.openDelay);
		} else {
			layerConfigList.forEach((layerConfigItem) => {
				if (layerConfigItem.guid === guid) {
					layerConfigItem.animElement.style.width = "";
					layerConfigItem.animElement.style.height = "";
					(layerConfigItem.animElement.style as any)["animation-name"] =
						layerConfigItem
							.animElement!.getAttribute("anim")!
							.replace("-reverse", "");
					if (
						pops.config.animation.hasOwnProperty(
							(layerConfigItem.animElement.style as any)["animation-name"]
						)
					) {
						layerConfigItem.animElement.style.display = "";
						if (layerConfigItem.maskElement) {
							layerConfigItem.maskElement.style.display = "";
						}
						function animationendCallBack() {
							popsDOMUtils.off(
								layerConfigItem.animElement,
								popsDOMUtils.getAnimationEndNameList(),
								animationendCallBack,
								{
									capture: true,
								}
							);
						}
						popsDOMUtils.on(
							layerConfigItem.animElement,
							popsDOMUtils.getAnimationEndNameList(),
							animationendCallBack,
							{
								capture: true,
							}
						);
					} else {
						layerConfigItem.animElement.style.display = "";
						if (layerConfigItem.maskElement) {
							layerConfigItem.maskElement.style.display = "";
						}
					}
				}
				return;
			});
		}
	},
	/**
	 * 关闭
	 * @param popsType
	 * @param layerConfigList
	 * @param guid
	 * @param config
	 * @param animElement
	 */
	close(
		popsType: string,
		layerConfigList: PopsLayerCommonConfig[],
		guid: string,
		config:
			| PopsAlertDetails
			| PopsDrawerDetails
			| PopsPromptDetails
			| PopsConfirmDetails
			| PopsIframeDetails
			| PopsLoadingDetails
			| PopsPanelDetails
			| PopsFolderDetails,
		animElement: HTMLElement
	) {
		let popsElement =
			animElement.querySelector<HTMLDivElement>(".pops[type-value]")!;
		let drawerConfig = config as Required<PopsDrawerDetails>;
		/**
		 * 动画结束事件
		 */
		function transitionendEvent() {
			function closeCallBack(event: Event) {
				if ((event as TransitionEvent).propertyName !== "transform") {
					return;
				}
				popsDOMUtils.off(
					popsElement,
					popsDOMUtils.getTransitionEndNameList(),
					void 0,
					closeCallBack
				);
				PopsInstanceUtils.removeInstance([layerConfigList], guid);
			}
			/* 监听过渡结束 */
			popsDOMUtils.on(
				popsElement,
				popsDOMUtils.getTransitionEndNameList(),
				closeCallBack
			);
			let popsTransForm = getComputedStyle(popsElement).transform;
			if (popsTransForm !== "none") {
				popsDOMUtils.trigger(
					popsElement,
					popsDOMUtils.getTransitionEndNameList(),
					void 0,
					true
				);
				return;
			}
			if (["top"].includes(drawerConfig.direction)) {
				popsElement.style.setProperty("transform", "translateY(-100%)");
			} else if (["bottom"].includes(drawerConfig.direction)) {
				popsElement.style.setProperty("transform", "translateY(100%)");
			} else if (["left"].includes(drawerConfig.direction)) {
				popsElement.style.setProperty("transform", "translateX(-100%)");
			} else if (["right"].includes(drawerConfig.direction)) {
				popsElement.style.setProperty("transform", "translateX(100%)");
			} else {
				console.error("未知direction：", drawerConfig.direction);
			}
		}

		if (popsType === "drawer") {
			setTimeout(() => {
				transitionendEvent();
			}, drawerConfig.closeDelay);
		} else {
			PopsInstanceUtils.removeInstance([layerConfigList], guid);
		}
	},
	/**
	 * 拖拽元素
	 * 说明：
	 * + 元素的position为absolute或者fixed
	 * + 会为元素的
	 * @param moveElement 需要拖拽的元素
	 * @param options 配置
	 */
	drag(
		moveElement: HTMLElement,
		options: {
			dragElement: HTMLElement;
			limit: boolean;
			triggerClick?: boolean;
			extraDistance: number;
			container?: Window | typeof globalThis | HTMLElement;
			moveCallBack?: (
				moveElement: HTMLElement,
				left: number,
				top: number
			) => void;
			endCallBack?: (
				moveElement: HTMLElement,
				left: number,
				top: number
			) => void;
			preventEvent?: (event: TouchEvent | PointerEvent) => boolean;
		}
	) {
		options = Object.assign(
			{
				limit: true,
				extraDistance: 3,
				container: PopsCore.globalThis,
				triggerClick: true,
			},
			options
		);
		let isMove = false;
		/* 点击元素，left偏移 */
		let clickElementLeftOffset = 0;
		/* 点击元素，top偏移 */
		let clickElementTopOffset = 0;
		let AnyTouch = popsUtils.AnyTouch();
		let anyTouchElement = new AnyTouch(options.dragElement, {
			preventDefault(event: Event) {
				if (typeof options.preventEvent === "function") {
					return options.preventEvent(event as any);
				} else {
					// 返回true阻止滑动
					return true;
				}
			},
		});
		popsDOMUtils.css(options.dragElement, {
			cursor: "move",
		});
		/**
		 * 获取移动元素的transform偏移
		 */
		function getTransform(element: HTMLElement) {
			let transform_left = 0;
			let transform_top = 0;
			let elementTransform =
				PopsCore.globalThis.getComputedStyle(element).transform;
			if (
				elementTransform !== "none" &&
				elementTransform != null &&
				elementTransform !== ""
			) {
				let elementTransformSplit = elementTransform
					.match(/\((.+)\)/)?.[1]
					.split(",")!;
				transform_left = Math.abs(parseInt(elementTransformSplit[4]));
				transform_top = Math.abs(parseInt(elementTransformSplit[5]));
			}
			return {
				transformLeft: transform_left,
				transformTop: transform_top,
			};
		}
		/**
		 * 修改移动的元素的style
		 */
		function changeMoveElementStyle(element: HTMLElement) {
			let old_transitionDuration = element.style.transitionDuration;
			if (globalThis.getComputedStyle(element).transitionDuration !== "0s") {
				element.style.transitionDuration = "0s";
			}
			return () => {
				element.style.transitionDuration = old_transitionDuration;
			};
		}
		/**
		 * 获取容器的高度、宽度，一般是window为容器
		 */

		function getContainerWidthOrHeight(
			container: HTMLElement | Window | typeof globalThis
		) {
			container = container ?? globalThis;
			return {
				width: popsDOMUtils.width(container),
				height: popsDOMUtils.height(container),
			};
		}
		/**
		 * 获取容器的最小left、top偏移
		 */

		function getContainerTopOrLeft(
			container: HTMLElement | Window | typeof globalThis
		) {
			container = container ?? globalThis;
			if (popsUtils.isWin(container)) {
				return {
					left: 0,
					top: 0,
				};
			} else {
				let rect = (container as HTMLElement).getBoundingClientRect();
				return {
					left: rect.left,
					top: rect.top,
				};
			}
		}
		let transformInfo = getTransform(moveElement);
		let transformLeft = transformInfo.transformLeft;
		let transformTop = transformInfo.transformTop;

		let resumeMoveElementStyle: Function | null = null;

		anyTouchElement.on("pan", function (event) {
			if (!isMove) {
				isMove = true;
				let rect = options.dragElement.getBoundingClientRect();
				clickElementLeftOffset = event.x - rect.left;
				clickElementTopOffset = event.y - rect.top;
				transformInfo = getTransform(moveElement);
				transformLeft = transformInfo.transformLeft;
				transformTop = transformInfo.transformTop;
				//if (event.nativeEvent.offsetX) {
				//  clickElementLeftOffset = parseInt(event.nativeEvent.offsetX);
				//} else {
				//  clickElementLeftOffset = parseInt(event.getOffset().x);
				//}
				//if (event.nativeEvent.offsetY) {
				//  clickElementTopOffset = parseInt(event.nativeEvent.offsetY);
				//} else {
				//  clickElementTopOffset = parseInt(event.getOffset().y);
				//}
				resumeMoveElementStyle = changeMoveElementStyle(moveElement);
			}

			/** 当前移动的left偏移 */
			let currentMoveLeftOffset =
				event.x - clickElementLeftOffset + transformLeft;
			/** 当前移动的top偏移 */
			let currentMoveTopOffset = event.y - clickElementTopOffset + transformTop;
			/* 拖拽移动 */
			if (event.phase === "move") {
				if (options.limit) {
					/* 限制在容器内移动 */
					/* left偏移最大值 */
					let maxLeftOffset =
						getContainerWidthOrHeight(options.container!).width -
						popsDOMUtils.width(moveElement) +
						transformLeft;
					let { left: minLeftOffset, top: minTopOffset } =
						getContainerTopOrLeft(options.container!);
					/* top偏移的最大值 */
					let maxTopOffset =
						getContainerWidthOrHeight(options.container!).height -
						popsDOMUtils.height(moveElement) +
						transformTop;
					if (currentMoveLeftOffset > maxLeftOffset) {
						/* 不允许超过容器的最大宽度 */
						currentMoveLeftOffset = maxLeftOffset;
					}
					if (currentMoveTopOffset > maxTopOffset) {
						/* 不允许超过容器的最大高度 */
						currentMoveTopOffset = maxTopOffset;
					}
					if (
						currentMoveLeftOffset - options.extraDistance * 2 <
						minLeftOffset + transformLeft
					) {
						/* 不允许left偏移小于容器最小值 */
						currentMoveLeftOffset = minLeftOffset + transformLeft;
						/* 最左边 +额外距离 */
						currentMoveLeftOffset += options.extraDistance;
					} else {
						/* 最右边 -额外距离 */
						currentMoveLeftOffset -= options.extraDistance;
					}
					if (
						currentMoveTopOffset - options.extraDistance * 2 <
						minTopOffset + transformTop
					) {
						/* 不允许top偏移小于容器最小值 */
						currentMoveTopOffset = minTopOffset + transformTop;
						/* 最上面 +额外距离 */
						currentMoveTopOffset += options.extraDistance;
					} else {
						/* 最下面 -额外距离 */
						currentMoveTopOffset -= options.extraDistance;
					}
				}
				if (typeof options.moveCallBack === "function") {
					options.moveCallBack(
						moveElement,
						currentMoveLeftOffset,
						currentMoveTopOffset
					);
				}

				popsDOMUtils.css(moveElement, {
					left: currentMoveLeftOffset + "px",
					top: currentMoveTopOffset + "px",
				});
			}

			/* 停止拖拽 */
			if (event.phase === "end") {
				isMove = false;
				if (typeof resumeMoveElementStyle === "function") {
					resumeMoveElementStyle();
					resumeMoveElementStyle = null;
				}
				if (typeof options.endCallBack === "function") {
					options.endCallBack(
						moveElement,
						currentMoveLeftOffset,
						currentMoveTopOffset
					);
				}
			}
		});
		if (options.triggerClick) {
			/* 因为会覆盖上面的点击事件，主动触发一下 */
			anyTouchElement.on(["tap"], function (event) {
				event.changedPoints.forEach((item) => {
					popsDOMUtils.trigger(
						item.target! as HTMLElement,
						"click",
						void 0,
						true
					);
				});
			});
		}
	},
	/**
	 * 排序数组
	 * @param getBeforeValueFun
	 * @param getAfterValueFun
	 * @param sortByDesc 排序是否降序，默认降序
	 */
	sortElementListByProperty<T extends any, R>(
		getBeforeValueFun: (value: T) => R,
		getAfterValueFun: (value: T) => R,
		sortByDesc = true
	) {
		if (typeof sortByDesc !== "boolean") {
			throw "参数 sortByDesc 必须为boolean类型";
		}
		if (getBeforeValueFun == null || getAfterValueFun == null) {
			throw "获取前面的值或后面的值的方法不能为空";
		}
		return function (after_obj: T, before_obj: T) {
			var beforeValue = getBeforeValueFun(before_obj); /*  前 */
			var afterValue = getAfterValueFun(after_obj); /* 后 */
			if (sortByDesc) {
				if (afterValue > beforeValue) {
					return -1;
				} else if (afterValue < beforeValue) {
					return 1;
				} else {
					return 0;
				}
			} else {
				if (afterValue < beforeValue) {
					return -1;
				} else if (afterValue > beforeValue) {
					return 1;
				} else {
					return 0;
				}
			}
		};
	},
};
