<template>
  <a-config-provider :locale="zhCN">
    <div class="miniprogram-editor">
      <div class="editor-toolbar">
        <a-space>
          <a-dropdown>
            <a-button>
              加载
              <DownOutlined />
            </a-button>
            <template #overlay>
              <a-menu v-if="historyList.length">
                <a-menu-item @click="onSelectDefault">
                  选择默认配置
                  <a-badge v-if="currentConfig?.activeHistoryId === 0" count="激活" />
                </a-menu-item>
                <a-menu-item
                  v-for="(item, index) in historyList"
                  :key="index"
                  @click="onSelectHistory(item.id!)"
                >
                  {{ item.name }}
                  <a-badge v-if="item.id === currentConfig?.activeHistoryId" count="激活" />
                </a-menu-item>
              </a-menu>
              <a-menu v-else>
                <a-menu-item disabled>暂无历史版本</a-menu-item>
              </a-menu>
            </template>
          </a-dropdown>
          <a-dropdown-button type="primary" @click="saveEditorJson">
            保存
            <template #overlay>
              <a-menu>
                <a-menu-item @click="openSaveAsModal">另存为历史版本</a-menu-item>
              </a-menu>
            </template>
          </a-dropdown-button>

          <div>
            <InfoCircleFilled />
            当前显示配置：
            <span>{{ currentShowConfigName }}</span>
          </div>

          <a-button v-if="currentConfig" @click="setActiveHistory">
            {{ currentConfig.activeHistoryId === currentHistoryId ? '已经是激活版本' : '设置为激活版本' }}
          </a-button>
          <a-button v-if="currentConfig && currentHistoryId !== 0" danger @click="deleteHistory">删除历史版本</a-button>
        </a-space>
        <a-button @click="exportToJsonFile">
          导出为JSON文件
          <DownloadOutlined />
        </a-button>
      </div>

      <!-- 另存为历史版本弹框 -->
      <a-modal
        v-model:open="saveAsModalVisible"
        title="另存为历史版本"
        ok-text="保存"
        cancel-text="取消"
        :confirm-loading="saveAsLoading"
        @ok="confirmSaveAs"
      >
        <a-form layout="vertical" class="save-as-form">
          <a-form-item label="版本名称">
            <a-input
              v-model:value="saveAsVersionName"
              placeholder="请输入版本名称"
              allow-clear
            />
          </a-form-item>
        </a-form>
      </a-modal>

      <!-- 添加页面弹框 -->
      <a-modal
        v-model:open="addPageModalVisible"
        title="添加页面"
        ok-text="添加"
        cancel-text="取消"
        :confirm-loading="addPageLoading"
        @ok="confirmAddPage"
      >
        <a-form layout="vertical" class="add-page-form">
          <a-form-item label="key（页面唯一标识）" required>
            <a-input
              v-model:value="addPageKey"
              placeholder="如 home、list_1"
              allow-clear
            />
          </a-form-item>
          <a-form-item label="title（页面标题）" required>
            <a-input
              v-model:value="addPageTitle"
              placeholder="如 首页、列表页"
              allow-clear
            />
          </a-form-item>
          <a-form-item v-if="addPageTemplate" label="模板">
            <span>{{ addPageTemplate }}</span>
          </a-form-item>
        </a-form>
      </a-modal>

      <div class="editor-body">
        <!-- 左一：页面列表 -->
        <div class="panel panel-pages">
          <div class="panel-title panel-title-with-action">
            <span>页面列表</span>
            <a-dropdown size="small">
              <PlusOutlined />
              <template #overlay>
                <a-menu @click="onAddPageMenuClick">
                  <a-menu-item key="Home">Home</a-menu-item>
                  <a-menu-item key="CommonList">CommonList</a-menu-item>
                  <a-menu-item key="Details">Details</a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </div>
          <a-list
            :data-source="currentEditorJson?.page ?? []"
            size="small"
            class="page-list"
          >
            <template #renderItem="{ item }">
              <a-list-item
                :class="{ 'page-item-active': selectedPage?.name === item.name }"
                class="page-list-item"
                @click="selectedPage = item"
              >
                <a-list-item-meta>
                  <template #title>{{ item.title || item.name }}</template>
                  <template #description>{{ item.name }} · {{ item.content?.type }}</template>
                </a-list-item-meta>
                <a-button
                  type="text"
                  danger
                  size="small"
                  class="page-item-delete"
                  @click.stop="confirmDeletePage(item)"
                >
                  <DeleteOutlined />
                </a-button>
              </a-list-item>
            </template>
          </a-list>
        </div>

        <!-- 左二：属性编辑器 -->
        <div class="panel panel-props">
          <div class="panel-title panel-title-with-action">
            属性编辑
            <a-button type="primary" size="small" @click="($refs.previewRef as any)?.refresh()">刷新</a-button>
          </div>
          <div v-if="!selectedPage" class="panel-empty">请选择页面</div>
          <PropsEditorTree
            v-else
            :page="selectedPage"
            v-model:testDetailId="testDetailId"
          />
        </div>

        <!-- 中间：预览 -->
        <div class="panel panel-preview">
          <div class="panel-title">小程序预览</div>
          <div class="preview-wrap">
            <EditorPreview
              ref="previewRef"
              :editor-json="currentEditorJson"
              :selected-page="selectedPage"
              :test-detail-id="testDetailId"
            />
          </div>
        </div>
      </div>
    </div>
  </a-config-provider>
</template>

<script setup lang="ts">
import { computed, onMounted, provide, ref } from 'vue';
import { ObjectUtils } from '@imengyu/imengyu-utils';
import { DownOutlined, DownloadOutlined, InfoCircleFilled, PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { message, Modal } from 'ant-design-vue';
import type { IHomeCommonCategoryDefine, IHomeCommonCategoryDetailDefine, IHomeCommonCategoryListDefine, IHomeCommonCategoryHomeDefine } from '../CommonCategoryDefine';
import DefaultEditorJson from '../DefaultCategory.json';
import PropsEditorTree from './subpart/PropsEditorTree.vue';
import EditorPreview from './subpart/EditorPreview.vue';
import zhCN from 'ant-design-vue/es/locale/zh_CN';
import CommonCategoryApi, { type ICommonCategoryConfigItem } from '../api/CommonCategoryApi';

/** 历史版本列表项（接口返回的 items 元素） */
interface IHistoryListItem {
  id?: number;
  data?: IHomeCommonCategoryDefine;
  createTime?: string;
  [key: string]: any;
}

const currentEditorJson = ref<IHomeCommonCategoryDefine>(DefaultEditorJson as IHomeCommonCategoryDefine);
const selectedPage = ref<(IHomeCommonCategoryDefine['page'][0]) | null>(null);
const pageList = computed(() => currentEditorJson.value.page || []);
const historyList = ref<IHistoryListItem[]>([]);
const currentConfig = ref<ICommonCategoryConfigItem>();
const currentHistoryId = ref<number>(0);
const currentShowConfigName = computed(() => {
  if (currentHistoryId.value === 0)
    return '默认配置';
  else
    return historyList.value.find(item => item.id === currentHistoryId.value)?.name ?? '未知';
});

const testDetailId = ref<number>(0);

const saveAsModalVisible = ref(false);
const saveAsVersionName = ref('');
const saveAsLoading = ref(false);

const addPageModalVisible = ref(false);
const addPageTemplate = ref<'Home' | 'CommonList' | 'Details' | null>(null);
const addPageKey = ref('');
const addPageTitle = ref('');
const addPageLoading = ref(false);

provide('pageList', pageList);

/** 生成新页面唯一 name */
function getUniquePageName(prefix: string): string {
  const pages = currentEditorJson.value?.page ?? [];
  const names = new Set(pages.map(p => p.name));
  let name = prefix;
  let n = 1;
  while (names.has(name)) {
    name = `${prefix}_${n}`;
    n++;
  }
  return name;
}

/** Home 模板 */
function createHomePageTemplate(): IHomeCommonCategoryHomeDefine {
  return {
    type: 'Home',
    props: {
      title: '首页',
      subTitle: '',
      homeBanner: '',
      homeButtons: [],
      categorys: [],
    },
  };
}

/** CommonList 模板 */
function createCommonListPageTemplate(): IHomeCommonCategoryListDefine {
  return {
    type: 'CommonList',
    props: {
      showTab: true,
      showSearch: true,
      showTotal: true,
      tabs: [],
    },
  };
}

/** Details 模板 */
function createDetailPageTemplate(): IHomeCommonCategoryDetailDefine {
  return {
    type: 'Details',
    props: {
      showHead: true,
      introBlockDescs: [],
      introBlocks: [],
      tabs: [],
    },
  };
}

function onAddPageMenuClick(e: { key: string }) {
  const template = e.key as 'Home' | 'CommonList' | 'Details';
  addPageTemplate.value = template;
  const prefixMap = { Home: 'home', CommonList: 'list', Details: 'detail' } as const;
  const titleMap = { Home: '首页', CommonList: '列表页', Details: '详情页' } as const;
  addPageKey.value = getUniquePageName(prefixMap[template] ?? 'page');
  addPageTitle.value = titleMap[template] ?? '页面';
  addPageModalVisible.value = true;
}

function confirmAddPage(): Promise<void> | void {
  const key = addPageKey.value?.trim();
  const title = addPageTitle.value?.trim();
  if (!key) {
    message.warning('请输入 key');
    return Promise.reject();
  }
  if (!title) {
    message.warning('请输入 title');
    return Promise.reject();
  }
  const pages = currentEditorJson.value?.page ?? [];
  const exists = pages.some(p => p.name === key);
  if (exists) {
    message.warning(`key「${key}」已存在，请使用其他 key`);
    return Promise.reject();
  }
  const template = addPageTemplate.value;
  if (!template) return Promise.reject();
  addPageLoading.value = true;
  let content: IHomeCommonCategoryHomeDefine | IHomeCommonCategoryListDefine | IHomeCommonCategoryDetailDefine;
  switch (template) {
    case 'Home':
      content = createHomePageTemplate();
      break;
    case 'CommonList':
      content = createCommonListPageTemplate();
      break;
    case 'Details':
      content = createDetailPageTemplate();
      break;
    default:
      message.warning(`不支持的模板：${template}`);
      return Promise.reject();
  }
  currentEditorJson.value = {
    ...currentEditorJson.value,
    page: [...pages, { name: key, title, content }],
  };
  const added = currentEditorJson.value.page[currentEditorJson.value.page.length - 1];
  selectedPage.value = added;
  addPageModalVisible.value = false;
  addPageLoading.value = false;
  message.success(`已添加页面 ${title} (${key})`);
}

function confirmDeletePage(page: IHomeCommonCategoryDefine['page'][0]) {
  Modal.confirm({
    title: '确认删除',
    content: `确定要删除页面「${page.title || page.name}」吗？删除后不可恢复。`,
    okText: '删除',
    okType: 'danger',
    cancelText: '取消',
    onOk() {
      const pages = currentEditorJson.value?.page ?? [];
      const index = pages.findIndex(p => p.name === page.name);
      if (index === -1) return;
      const next = pages.filter(p => p.name !== page.name);
      currentEditorJson.value = { ...currentEditorJson.value, page: next };
      if (selectedPage.value?.name === page.name)
        selectedPage.value = next[0] ?? null;
      message.success('已删除页面');
    },
  });
}

async function loadEditorJson(selectDefault = false) {
  try {
    //加载基础配置
    currentConfig.value = await CommonCategoryApi.getConfigWithoutCache();
    if (!currentConfig.value)
      throw new Error('加载基础配置失败');
    if (selectDefault) 
      currentHistoryId.value = currentConfig.value.activeHistoryId;
    //根据activeHistoryId选择当前激活的历史版本
    if (currentHistoryId.value > 0) {
      const activeHistory = historyList.value.find(item => item.id === currentHistoryId.value);
      if (activeHistory) 
        currentEditorJson.value = ObjectUtils.clone(activeHistory.data!) as IHomeCommonCategoryDefine;
      else
        throw new Error('当前激活的历史版本不存在');
    } else {
      currentEditorJson.value = ObjectUtils.clone(currentConfig.value.data) as IHomeCommonCategoryDefine;
    }
    message.success('加载分类成功');
  } catch (error) {
    Modal.error({
      title: '加载分类失败',
      content: '' + error,
    });
  }
}
async function loadEditorJsonHistorys() {
  try {
    const res = await CommonCategoryApi.getConfigHistoryList(1, 10);
    const items = res?.items ?? [];
    historyList.value = Array.isArray(items) ? items : [];
  } catch (error) {
    historyList.value = [];
    Modal.error({
      title: '加载历史版本列表失败',
      content: '' + error,
    });
  }
}

function onSelectDefault() {
  currentHistoryId.value = 0;
  loadEditorJson(true);
}
function onSelectHistory(id: number) {
  currentHistoryId.value = id;
  loadEditorJson(false);
}

/** 默认保存：根据 currentHistoryId 保存到默认配置或指定历史版本 */
async function saveEditorJson() {
  try {
    const saveToHistoryId = currentHistoryId.value === 0 ? undefined : currentHistoryId.value;
    await CommonCategoryApi.editConfig(
      currentEditorJson.value,
      undefined,
      saveToHistoryId
    );
    message.success('保存成功');
  } catch (error) {
    Modal.error({
      title: '保存失败',
      content: '' + error,
    });
  }
}

function openSaveAsModal() {
  saveAsVersionName.value = '';
  saveAsModalVisible.value = true;
}

async function confirmSaveAs() {
  const name = saveAsVersionName.value?.trim();
  if (!name) {
    message.warning('请输入版本名称');
    return;
  }
  saveAsLoading.value = true;
  try {
    await CommonCategoryApi.editConfig(
      currentEditorJson.value,
      name,
      0
    );
    message.success('已另存为历史版本');
    saveAsModalVisible.value = false;
    await loadEditorJsonHistorys();
  } catch (error) {
    Modal.error({
      title: '另存为失败',
      content: '' + error,
    });
  } finally {
    saveAsLoading.value = false;
  }
}

async function setActiveHistory() {
  await CommonCategoryApi.setActiveConfigHistory(currentHistoryId.value);
  message.success('设置为激活版本成功');
}
async function deleteHistory() {
  Modal.confirm({
    title: '删除历史版本',
    content: '确定要删除该历史版本吗？',
    onOk: async () => {
      await CommonCategoryApi.deleteConfigHistory(currentHistoryId.value);
      message.success('删除历史版本成功');
      await loadEditorJsonHistorys();
      await loadEditorJson(true);
    },
  });
}

function exportToJsonFile() {
  const json = JSON.stringify(currentEditorJson.value);
  const blob = new Blob([json], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'editor.json';
  a.click();
}

onMounted(async () => {
  await loadEditorJsonHistorys();
  await loadEditorJson(true);
  window.addEventListener('beforeunload', function(e) {
    const message = '你还有未保存的内容，确定要离开吗？';
    e.returnValue = message;
    return message;
  });
})
</script>

<style scoped>
.miniprogram-editor {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: #f5f5f5;
}
.editor-toolbar {
  padding: 8px 16px;
  background: #fff;
  border-bottom: 1px solid #eee;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.editor-body {
  flex: 1;
  display: flex;
  overflow: hidden;
  min-height: 0;
}
.panel {
  background: #fff;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-right: 1px solid #eee;
}
.panel:last-of-type {
  border-right: none;
}
.panel-title {
  padding: 8px 12px;
  font-weight: 600;
  border-bottom: 1px solid #eee;
  flex-shrink: 0;
}
.panel-title-with-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.panel-pages {
  width: 220px;
  flex-shrink: 0;
}
.panel-props {
  width: 720px;
  flex-shrink: 0;
}
.panel-preview {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 16px;
  overflow: auto;
}
.panel-empty {
  padding: 16px;
  color: #999;
  font-size: 12px;
}
.page-list {
  flex: 1;
  overflow: auto;
}
.page-list :deep(.ant-list-item) {
  cursor: pointer;
  padding: 8px 12px;
}
.page-list-item :deep(.ant-list-item-meta) {
  flex: 1;
  min-width: 0;
}
.page-list-item {
  display: flex;
  align-items: center;
  gap: 4px;
}
.page-item-delete {
  flex-shrink: 0;
  padding: 0 4px;
}
.page-item-active {
  background: #e6f7ff;
}
.preview-wrap {
  width: 100%;
  max-width: 450px;
  aspect-ratio: 9 / 16;
  overflow: auto;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  margin: 0 auto;
}
</style>
