<template>
	<el-scrollbar>
		<div class="dp-wrap">
			<dp-lump :ref="setRefs('lump')" />

			<div class="dp-device">
				<div class="tool">
					<slot name="tool"></slot>
				</div>
				<div
					class="device"
					:style="{
						backgroundColor: body.backgroundColor,
						backgroundImage: 'url(' + body.backgroundImage + ')'
					}"
				>
					<div
						:class="[
							{
								'header-fixed': header.component?.props?.fixed
							}
						]"
					></div>
					<div
						:style="{
							backgroundColor: header.component?.props?.backgroundColor,
							color: header.component?.props?.color
						}"
						class="nav"
						:class="[
							{
								'nav-border': header.component?.props?.border,
								'nav-fixed': header.component?.props?.fixed
							}
						]"
						@click="toDet(header)"
					>
						{{ header.component?.props?.title }}
					</div>
					<!-- 悬浮按钮 -->
					<template v-if="suspensionData?.name">
						<fix-suspension v-bind="suspensionData.component.props" />
					</template>
					<el-scrollbar class="scrollbar" :ref="setRefs('scrollbar')">
						<draggable
							v-model="pageData"
							class="list"
							tag="div"
							item-key="id"
							:group="{
								name: 'A',
								animation: 300,
								ghostClass: 'Ghost',
								dragClass: 'Drag',
								draggable: '.is-drag'
							}"
						>
							<template #item="{ element: item, index }">
								<div
									class="item"
									:class="{
										active: pageActive == item.id
									}"
									@click="toDet(item)"
								>
									<el-icon
										class="close"
										@click.stop="remove(index)"
										v-show="pageActive == item.id"
									>
										<close-bold />
									</el-icon>
									<component
										:is="item.component.name"
										:data="item"
										:key="item.id"
										v-bind="item.component.props"
									/>
								</div>
							</template>

							<template #footer>
								<div class="tips">点击或者拖动组件添加</div>
							</template>
						</draggable>
					</el-scrollbar>
				</div>
			</div>

			<dp-config />
		</div>
	</el-scrollbar>
</template>
<script lang="ts" setup>
import { onMounted, provide, nextTick, ref } from "vue";
import Draggable from "vuedraggable/src/vuedraggable";
import { CloseBold } from "@element-plus/icons-vue";
import { storage, useCool } from "/@/cool";
import DpConfig from "./config.vue";
import DpLump from "./lump.vue";
import { Dp } from "../types";
import { useData } from "../data";

// 类型定义
interface BodyData {
	backgroundColor: string;
	backgroundImage: string;
}

// 使用 Cool 相关功能
const { mitt, refs, setRefs, service } = useCool();
const { Header } = useData();

// 响应式数据
const pageData = ref<Dp.Item[]>([]);
const pageActive = ref<string>("");
const suspensionData = ref<Dp.Item | null>(null);
const header = ref<Dp.Item>(Header);
const body = ref<BodyData>({ backgroundColor: "#f7f8fa", backgroundImage: "" });

// 设置 BODY 数据
const setBody = (data: BodyData) => (body.value = data);

// 设置头部组件
const setHeader = (data: Dp.Item) => {
	data.config = Header.config;
	header.value = data;
};

// 设置悬浮按钮组件
const handleSuspension = (data: Dp.Item) => {
	if (suspensionData.value === null) {
		suspensionData.value = data;
	}
	toDet(suspensionData.value);
};

const setSuspension = (data: Dp.Item) => {
	data.config = refs.lump.getConfig(data.name);
	suspensionData.value = data;
};

// 设置页面数据
const setFormList = (list: Dp.Item[]) => {
	pageData.value = list.map((e) => ({ ...e, config: refs.lump.getConfig(e.name) }));
	toDet(pageData.value[0]);
};

// 组件配置详情
const toDet = (item?: Dp.Item) => {
	if (!item) return;
	pageActive.value = item.id;
	mitt.emit("dp.setConfig", {
		options: item,
		cb: (obj: any) => {
			if (item.name === "header") {
				header.value.component.props = obj;
			} else if (item.name === "suspension") {
				suspensionData.value!.component.props = obj;
			} else {
				const index = pageData.value.findIndex((e) => e.id === item.id);
				if (index !== -1) {
					Object.assign(pageData.value[index].component.props, obj);
				}
			}
		}
	});
};

// 添加组件
const add = (data: Dp.Item) => {
	if (data.name === "suspension") {
		handleSuspension(data);
	} else {
		pageData.value.push(data);
		toDet(data);
	}
};

// 清空组件配置
const clearConfig = (id?: string) => {
	if (pageActive.value === id || !id) {
		mitt.emit("dp.clearConfig");
	}
};

// 删除组件
const remove = (index: number) => {
	if (index >= 0 && index < pageData.value.length) {
		clearConfig(pageData.value[index].id);
		pageData.value.splice(index, 1);
		if (pageData.value.length) {
			toDet(pageData.value[Math.max(index - 1, 0)]);
		}
	}
};

// 根据 ID 删除组件
const removeBy = ({ id, index }: { id?: string; index?: number }) => {
	if (id) {
		index = pageData.value.findIndex((e) => e.id === id);
	}
	remove(index ?? -1);
};

// 删除悬浮按钮
const removeSuspension = () => (suspensionData.value = null);

// 清空列表
const clear = () => {
	clearConfig();
	pageData.value = [];
};

// 设置选中组件
const setActive = (id: string) => {
	const item = pageData.value.find((e) => e.id === id);
	if (item) {
		toDet(item);
	}
};
// 删除 props 带有 - 的属性
function removeHyphenatedPropertiesFromProps(props: Record<string, any>): Record<string, any> {
	if (props === null || typeof props !== "object") {
		return props;
	}

	// 创建一个新对象，用于存储不含 `-` 的属性
	const result: Record<string, any> = {};
	for (const [key, value] of Object.entries(props)) {
		// 如果属性名不包含 `-`，则将属性添加到结果对象中
		if (!key.includes("-")) {
			result[key] = value;
		}
	}
	return result;
}

// 获取数据列表
const getData = () => {
	const deep = (arr: Dp.Item[]): any[] => {
		const data = arr.map((e) => {
			e.component.props = removeHyphenatedPropertiesFromProps(e.component.props);
			return {
				id: e.id,
				name: e.name,
				isOnly: e.isOnly || false,
				label: e.component?.props?.label,
				component: e.component
			};
		});
		if (suspensionData.value) {
			// 悬浮按钮
			const suspension = {
				id: suspensionData.value.id,
				name: suspensionData.value.name,
				label: suspensionData.value.label,
				isOnly: true,
				component: suspensionData.value.component
			};
			data.push(suspension);
		}
		const headerData = {
			id: header.value.id,
			name: header.value.name,
			label: header.value.label,
			isOnly: true,
			component: header.value.component
		};
		data.unshift(headerData);
		return data;
	};

	return deep(pageData.value);
};

// 检查是否唯一组件
const hasTemp = (name: string) => pageData.value.some((e) => e.name === name && e.isOnly);

// 检查是否存在了悬浮按钮
const hasSuspension = () => {
	return !(suspensionData.value === null);
};
// 保存草稿
const saveDraft = () => {
	storage.set(
		"design.pageCode",
		pageData.value.map((e) => ({ ...e, config: undefined }))
	);
};

// 获取草稿
const getDraft = () => {
	const list: Dp.Item[] = storage.get("design.pageCode") || [];
	pageData.value = list.map((e) => ({ ...e, config: refs.lump.getConfig(e.name) }));
	toDet(pageData.value[0]);
};

// 滚动到底部
const scrollToBottom = () =>
	nextTick(() => {
		if (refs.scrollbar) {
			refs.scrollbar.scrollTo(0, 9999);
		}
	});

// 监听选中事件
mitt.on("dp.setActive", setActive);

// 提供和暴露 API
const dp = {
	pageData,
	pageActive,
	getData,
	toDet,
	setActive,
	add,
	remove,
	removeSuspension,
	removeBy,
	clear,
	hasTemp,
	hasSuspension,
	clearConfig,
	saveDraft,
	scrollToBottom,
	setHeader,
	setSuspension,
	setBody,
	setFormList
};

provide("dp", dp);
defineExpose(dp);

onMounted(() => {
	// 如果需要在挂载时加载草稿，取消注释
	// getDraft();
});
</script>

<style lang="scss">
.Ghost {
	opacity: 0.7;
}
</style>

<style lang="scss">
.dp-wrap {
	display: flex;
	height: 100%;
	min-height: 700px;
	background-color: #edf0f3;
	padding: 10px;
	box-sizing: border-box;
	color: #000;

	.dp-device {
		display: flex;
		justify-content: center;
		align-items: center;
		flex: 1;
		position: relative;
		.tool {
			position: absolute;
			right: 20px;
			top: 20px;
		}

		.header-fixed {
			height: 54px;
		}

		.device {
			position: relative;
			height: 667px;
			width: 360px;
			overflow: hidden;
			border-radius: 20px;
			background-color: #f7f8fa;
			background-size: contain;
			background-position: top center;
			background-repeat: no-repeat;

			.nav {
				display: flex;
				align-items: center;
				justify-content: center;
				height: 54px;
				font-size: 18px;
				background-color: #fff;
				cursor: pointer;
			}

			.nav-border {
				border-bottom: 1px solid #eee;
			}
			.nav-fixed {
				position: absolute;
				top: 0;
				left: 0;
				right: 0;
				z-index: 999;
			}

			.scrollbar {
				height: 612px;
				width: 100%;
				box-sizing: border-box;

				.list {
					height: 100%;
					padding-bottom: 20px;
					box-sizing: border-box;

					.item {
						position: relative;
						box-sizing: border-box;
						cursor: pointer;
						width: 100%;

						&:last-child {
							margin-bottom: 0;
						}

						.close {
							position: absolute;
							right: 0;
							top: 0;
							height: 14px;
							width: 14px;
							color: #fff;
							z-index: 9;
							background-color: var(--color-primary);
							padding: 1px;
							cursor: pointer;

							&:hover {
								background-color: red;
							}
						}

						&.sortable-ghost {
							display: flex;
							align-items: center;
							min-height: 40px;
							width: 100%;
							padding: 0 18px;
							box-sizing: border-box;
							border: 1px dashed currentColor;
							border-radius: 3px;
							cursor: pointer;
							color: #bfbfbf;
							background-color: #fff;
							opacity: 0.8;

							img {
								height: 20px;
								width: 20px;
								margin-right: 14px;
							}

							span {
								font-size: 16px;
							}

							[class^="lump-"] {
								width: 100%;
								color: #fff;

								.placeholder {
									color: #fff;
								}
							}
						}

						&.active {
							&::after {
								display: block;
								content: "";
								position: absolute;
								left: 0;
								top: 0;
								z-index: 99;
								height: 100%;
								width: 100%;
								border: 2px solid var(--color-primary);
								box-sizing: border-box;
								pointer-events: none;
							}
						}
					}
				}
			}

			.tips {
				text-align: center;
				font-size: 14px;
				padding: 10px 0 20px 0;
				color: #999;
			}
		}
	}
}
</style>
