import type { ProjectInfo, Page, ReferLine, CustomElement } from "#/project";
import { defineStore } from "pinia";
import { asyncComponentAll } from "@shalu/dashboard-ui";
import { ScreenFillEnum } from "@/enum/screenFillEnum";
import { update, defaultsDeep } from "lodash";
import { getNormalizedContainer } from "@/utils/common";
import { editPageDesignApi } from "@shalu/service";
import { message } from "ant-design-vue";
import { buildHtml, buildJs } from "@/utils/build";

type ProjectState = {
  projectInfo: ProjectInfo;
  activePageIndex: number;
  addCompData: {
    key: string;
    name: string;
    componentType: string;
    container: {
      style: Record<string, any>;
      props: Record<string, any>;
    };
  } | null;
  mode: "edit" | "player";
  selectedElementKeys: string[];
  showReffer: boolean;
};
const defaultPage: Page = {
  key: "1",
  name: "页面1",
  background: {
    type: "color",
    color: "#0B074BFF",
    image: "",
    fillType: "",
  },
  elements: [],
  referLines: [],
};
const CURRENT_PROJECT = "currentProject";

export const useProjectStore = defineStore({
  id: "project",
  state: (): ProjectState => ({
    // 项目信息
    projectInfo: {
      pageId: "",
      name: "",
      description: "",
      sizeType: "",
      width: 0,
      height: 0,
      fillType: ScreenFillEnum.AUTO,
      pages: [{ ...defaultPage }],
    },
    // 当前编辑页面索引
    activePageIndex: 0,
    // 添加组件临时数据
    addCompData: null,
    // 视图模式
    mode: "edit",
    // 选中的元素
    selectedElementKeys: [],
    // 辅助线
    showReffer: true,
  }),
  getters: {
    // 参考线
    referLines(state) {
      return state.projectInfo.pages[state.activePageIndex].referLines;
    },
    // 当前全部元素
    elements(state) {
      return state.projectInfo.pages[state.activePageIndex].elements;
    },
    // 当前页面
    currentPage(state) {
      return state.projectInfo.pages[state.activePageIndex];
    },
    // 当前选中元素
    currentSelectedElements(state) {
      const list: CustomElement[] = [];
      state.projectInfo.pages[state.activePageIndex].elements.forEach((item) => {
        if (state.selectedElementKeys.includes(item.key)) {
          list.push(item);
        }
        // 为组时，遍历组下面成员
        if (item.children) {
          item.children.forEach((child) => {
            if (state.selectedElementKeys.includes(child.key)) {
              list.push(child);
            }
          });
        }
      });
      return list;
    },
  },
  actions: {
    setProjectInfo(info: any) {
      this.projectInfo = info;
      localStorage.setItem(CURRENT_PROJECT, JSON.stringify(info));
    },
    createProject() {
      const project = {
        name: "新建项目",
        description: "这是一个新建项目",
        sizeType: "custom",
        width: 1280,
        height: 720,
        fillType: ScreenFillEnum.AUTO,
        pages: [{ ...defaultPage }],
      };
      this.setProjectInfo(project as unknown as ProjectInfo);
      return project;
    },
    getCurrentProjectInfo(): ProjectInfo | undefined {
      let info = JSON.parse(localStorage.getItem(CURRENT_PROJECT) || "null");
      if (!info) {
        info = {
          name: "默认项目",
          description: "这是一个默认项目",
          sizeType: "custom",
          width: 1280,
          height: 720,
          fillType: ScreenFillEnum.AUTO,
          pages: [{ ...defaultPage }],
        };
      }
      this.setProjectInfo(info as unknown as ProjectInfo);
      return info;
    },
    updateProjectInfo(info: any) {
      Object.assign(this.projectInfo, info);
    },
    updateProjectInfoByPath(path: string, payload: any) {
      update(this.projectInfo, path, () => payload);
    },
    addReferLine(line: ReferLine) {
      this.projectInfo.pages[this.activePageIndex].referLines.push(line);
    },
    removeReferLine(key: string) {
      const index = this.referLines.findIndex((line) => line.key === key);
      index !== -1 &&
        this.projectInfo.pages[this.activePageIndex].referLines.splice(
          index,
          1
        );
    },
    updateReferLine(line: ReferLine) {
      const index = this.referLines.findIndex((l) => l.key === line.key);
      if (index !== -1) {
        this.projectInfo.pages[this.activePageIndex].referLines[index] = line;
      }
    },
    // 添加组件
    async addElement(element: any, position?: 'center', cancelSelect: boolean = false) {
      this.addCompData = null;
      if (!element) return;

      // 组合
      if(element.componentType === 'group') {
        this.projectInfo.pages[this.activePageIndex].elements.push(element);
        this.selectedElementKeys = [element.key];
        return;
      }

      const elements = this.projectInfo.pages[this.activePageIndex].elements;
      // 获取每个自定义组件暴露出来的默认属性
      const { defaultPropsValue } =
        (await asyncComponentAll[element.componentType as keyof typeof asyncComponentAll]?.()) || {};

      const { defaultWidth = 400, defaultHeight = 260 } =
        defaultPropsValue?.container?.props || {};
      const { props: containerDefaultProps = {}, style: containerDefaultStyle = {} } =
        defaultPropsValue?.container || {};

      const index =
        elements.filter((item) => item.componentType === element.componentType)
          .length + 1;

      const { x, y, width, height } = element.container.props;
      const container = getNormalizedContainer({
        containerDefaultStyle,
        props: {
          ...containerDefaultProps,
          width: width ?? defaultWidth,
          height: height ?? defaultHeight,
          // 判断是否需要居中，是的话需要减去宽高的一半
          x: position === 'center' ? x - defaultWidth / 2 : x,
          y: position === 'center' ? y - defaultHeight / 2 : y,
        },
      });
      // 添加组件
      this.projectInfo.pages[this.activePageIndex].elements.push({
        ...defaultsDeep(element, defaultPropsValue),
        name: element.name + index,
        zIndex: elements.length + 1,
        visible: true,
        locked: false,
        container,
      });

      if(!cancelSelect) this.selectedElementKeys = [element.key];
    },
    // 更新组件
    updateElement(key: string, path: string, payload: any) {
      const pageIndex = this.activePageIndex;

      const element = this.projectInfo.pages[pageIndex].elements.find((item) => item.key === key);
      const elementIndex = this.projectInfo.pages[pageIndex].elements.findIndex((item) => item.key === key);

      // 如果是锁定状态不能修改宽高 位置
      if (
        element &&
        element.locked &&
        [
          "container.props.width",
          "container.props.height",
          "container.props.x",
          "container.props.y",
        ].includes(path)
      )
        return;

      if (element) {
        update(this.projectInfo.pages[pageIndex].elements[elementIndex], path, () => payload);
      }
    },
    // 删除组件
    removeElement(key: string) {
      const index = this.projectInfo.pages[
        this.activePageIndex
      ].elements.findIndex((item) => item.key === key);
      if (index !== -1) {
        this.projectInfo.pages[this.activePageIndex].elements.splice(index, 1);
      }
    },
    // 设置临时添加组件数据
    setAddCompData(data: any) {
      this.addCompData = data;
    },
    // 清除临时添加组件数据
    clearAddCompData() {
      this.addCompData = null;
    },
    setMode(mode: "edit" | "player") {
      this.mode = mode;
    },
    // 设置选中的元素
    setSelectedElementKeys(keys: string[]) {
      this.selectedElementKeys = keys;
    },
    // 删除所有选中的元素
    clearAllSelectedElement() {
      this.selectedElementKeys = [];
    },
    // 设置当前页面背景
    setCurrentPageBackground(background: any) {
      this.projectInfo.pages[this.activePageIndex].background = background;
    },
    setFillType(fillType: ScreenFillEnum) {
      this.projectInfo.fillType = fillType;
    },
    // 保存当前项目到服务器
    async handleSaveProject(pageId: string) {
      const html = buildHtml(this.projectInfo);
      const js = buildJs(this.projectInfo);

      const params = {
        appPageId: pageId,
        json: JSON.stringify(this.projectInfo),
        html,
        js,
        type: 0,
      };

      editPageDesignApi(params);
      message.success("保存成功");
    },
    // 切换辅助线隐藏
    toggleReffer() {
      this.showReffer = !this.showReffer;
    }
  },
});
