import {
	defineComponent,
	nextTick,
	onMounted,
	reactive,
	ref,
	h,
	render,
	toRaw,
	type PropType
} from "vue";
import { isString } from "lodash-es";
import { addClass, contains, removeClass } from "../../utils";
import { useRefs } from "../../hooks";
import { ElIcon } from "element-plus";
import { ArrowRight } from "@element-plus/icons-vue";

const ClContextMenu = defineComponent({
	name: "cl-context-menu",

	props: {
		show: Boolean,
		options: {
			type: Object as PropType<ClContextMenu.Options>,
			default: () => ({})
		},
		event: {
			type: Object,
			default: () => ({})
		}
	},

	setup(props, { expose, slots }) {
		const { refs, setRefs } = useRefs();

		// 是否可见
		const visible = ref(props.show || false);

		// 按钮列表
		const list = ref<ClContextMenu.Item[]>([]);

		// 样式
		const style = reactive({
			left: "0px",
			top: "0px"
		});

		// 选中值
		const ids = ref("");

		// 阻止默认事件
		function stopDefault(e: any) {
			if (e.preventDefault) {
				e.preventDefault();
			}

			if (e.stopPropagation) {
				e.stopPropagation();
			}
		}

		// 解析列表
		function parseList(list: ClContextMenu.Item[]) {
			function deep(list: ClContextMenu.Item[]) {
				list.forEach((e) => {
					e.showChildren = false;

					if (e.children) {
						deep(e.children);
					}
				});
			}

			deep(list);

			return list;
		}

		// 目标元素
		let targetEl: any;

		// 关闭
		function close() {
			visible.value = false;
			ids.value = "";

			if (targetEl) {
				removeClass(targetEl, "cl-context-menu__target");
			}
		}

		// 打开
		function open(event: any, options: ClContextMenu.Options = {}) {
			// 阻止默认事件
			stopDefault(event);

			// 显示
			visible.value = true;

			// 元素
			const el = refs["context-menu"].querySelector(".cl-context-menu__box") as HTMLElement;

			// 点击样式
			if (options?.hover) {
				const d = options.hover === true ? {} : options.hover;
				targetEl = event.target;

				if (targetEl && isString(targetEl.className)) {
					if (d.target) {
						while (!targetEl.className.includes(d.target)) {
							targetEl = targetEl.parentNode;
						}
					}

					addClass(targetEl, d.className || "cl-context-menu__target");
				}
			}

			// 自定义样式
			if (options?.class) {
				addClass(el, options.class);
			}

			// 菜单列表
			if (options?.list) {
				list.value = parseList(options.list);
			}

			nextTick(() => {
				// 计算位置
				let left = event.pageX;
				let top = event.pageY;

				// 组件方式用 offset 计算
				if (!props.show) {
					left = event.offsetX;
					top = event.offsetY;
				}

				const { clientHeight: h1, clientWidth: w1 } = event.target?.ownerDocument.body;
				const { clientHeight: h2, clientWidth: w2 } = el;

				if (top + h2 > h1) {
					top = h1 - h2 - 5;
				}

				if (left + w2 > w1) {
					left = w1 - w2 - 5;
				}

				style.left = left + "px";
				style.top = top + "px";
			})

			return {
				close
			};
		}

		// 行点击
		function rowClick(item: ClContextMenu.Item, id: string) {
			ids.value = id;

			if (item.disabled) {
				return false;
			}

			if (item.callback) {
				return item.callback(close);
			}

			if (item.children) {
				item.showChildren = !item.showChildren;
			} else {
				close();
			}
		}

		expose({
			open,
			close
		});

		onMounted(function () {
			if (visible.value) {
				const { body, documentElement } = props.event.target.ownerDocument;

				// 添加到 body 下
				body.appendChild(refs["context-menu"]);
				// 关闭事件
				(documentElement || body).addEventListener("mousedown", (e: any) => {
					const el = refs["context-menu"];
					if (!contains(el, e.target) && el != e.target) {
						close();
					}
				});

				// 默认打开
				open(props.event, props?.options);
			}
		});

		return () => {
			function deep(list: ClContextMenu.Item[], pId: string, level: number) {
				return (
					<div class={["cl-context-menu__box", level > 1 && "is-append"]}>
						{list
							.filter((e) => !e.hidden)
							.map((e, i) => {
								const id = `${pId}-${i}`;

								if (!e.suffixIcon) {
									// 默认图标
									if (e.children) {
										e.suffixIcon = ArrowRight;
									}
								}

								return (
									<div
										class={{
											"is-active": ids.value.includes(id),
											"is-ellipsis": e.ellipsis ?? true,
											"is-disabled": e.disabled
										}}
										onClick={(ev: MouseEvent) => {
											rowClick(e, id);
											ev.stopPropagation();
										}}
									>
										{/* 前缀图标 */}
										{e.prefixIcon && <ElIcon>{h(toRaw(e.prefixIcon))}</ElIcon>}

										{/* 标题 */}
										<span>
											{e.label}
										</span>

										{/* 后缀图标 */}
										{e.suffixIcon && <ElIcon>{h(toRaw(e.suffixIcon))}</ElIcon>}

										{/* 子集 */}
										{e.children &&
											e.showChildren &&
											deep(e.children, id, level + 1)}
									</div>
								);
							})}
					</div>
				);
			}

			return (
				visible.value && (
					<div
						class="cl-context-menu"
						ref={setRefs("context-menu")}
						style={style}
						onContextmenu={stopDefault}>
						{slots.default ? slots.default() : deep(list.value, "0", 1)}
					</div>
				)
			);
		};
	}
});

export const ContextMenu = {
	open(event: any, options: ClContextMenu.Options) {
		const vm = h(ClContextMenu, {
			show: true,
			event,
			options
		});

		render(vm, event.target.ownerDocument.createElement("div"));

		return vm.component?.exposed as ClContextMenu.Exposed;
	}
};

export default ClContextMenu;
