<template>
  <Container
    :upload-resourse="uploadResourse"
    v-model:full="full"
    v-if="dataLoaded"
    :ref="(d: any) => initDraw(d?.draw)"
  >
    <template #header>
      <Header
        v-if="draw"
        :title="$t('tabulation.name1')"
        @screenshot="(val) => (needScreenshot = val)"
      />
    </template>
    <template #slide>
      <Slide v-if="draw" @update-map-image="setMapHandler" />
    </template>
  </Container>

  <Preview
    @change-origin="(origin) => setOrigin && setOrigin(origin)"
    :showLabelLine="coverSetting?.showViewportLabelLine"
    :cover-scale="coverSetting?.scale"
    :paperKey="tabulationData?.paperKey"
    :pixelRatio="needScreenshot ? needScreenshot : pixelRatio"
    :not-debounce="!!needScreenshot"
    :data="overviewData?.store"
    :tab-draw="draw"
    :scale="draw?.viewerConfig.scaleX"
    @change-config="(config) => (originConfig = config)"
    v-if="overviewData?.store.config?.proportion.scale"
  />
  <Dialog />
</template>

<script lang="ts" setup>
import Header from "./header.vue";
import Slide from "./slide.vue";
import Container from "../../../components/container/container.vue";
import {
  computed,
  nextTick,
  onUnmounted,
  reactive,
  ref,
  shallowRef,
  watch,
  watchEffect,
} from "vue";
import { Draw } from "../../../components/container/use-draw";
import Dialog from "../../../dialog/dialog.vue";
import {
  tabulationData,
  refreshTabulationData,
  tableCoverKey,
  tableCoverScaleKey,
  tableCompassKey,
  overviewData,
  refreshOverviewData,
} from "../../store";
import { ImageData } from "@/core/components/image";
import { TextData } from "@/core/components/text";
import { genTabulationData, getRealPixel, repTabulationStore } from "./gen-tab";
import { IconData } from "@/core/components/icon";
import { Transform } from "konva/lib/Util";
import { MathUtils } from "three";
import { components } from "@/core/components";
import { ShapeType } from "@/index";
import { copy, mergeFuns, round } from "@/utils/shared";
import { getImageSize } from "@/utils/shape";
import { tabCustomStyle } from "../defStyle";
import { defaultLayer } from "@/constant";
import { Size } from "@/utils/math";
import Preview from "./overview-viewport.vue";
import { Image } from "konva/lib/shapes/Image";
import { Group } from "konva/lib/Group";
import { getBaseItem } from "@/core/components/util";
import {
  getPaperConfig,
  paperConfigs,
  PaperKey,
} from "@/example/components/slide/actions";
import { getFixPosition } from "@/utils/bound";
import { listener } from "@/utils/event";
import { router } from "../../router";
import { params } from "@/example/env";
import { tableSerialTableKey } from "@/example/constant";
import { addTable, getCurrentNdxRaw, syncTable } from "@/core/components/serial";
import { ui18n } from "@/lang";

const uploadResourse = window.platform.uploadResourse;
const full = ref(false);
const draw = ref<Draw>();
const pixelRatio = ref(window.devicePixelRatio);

const setMap = async (config: { url: string; size: Size }) => {
  const store = tabulationData.value.store;
  const paperKey = tabulationData.value.paperKey;
  const compass = 0;

  if (config.url && config.size.height && config.size.width) {
    const size = await getImageSize(window.platform.getResource(config.url));
    const cover = {
      url: config.url,
      ...size,
      proportion: {
        scale: (config.size.width / size.width) * 1000,
        unit: "mm",
      },
    };
    if (!tabulationData.value.store.config) {
      const layer = await genTabulationData(paperKey, compass, cover);
      tabulationData.value.store.layers[defaultLayer] = layer;
    } else {
      await repTabulationStore(paperKey, compass, cover, store);
    }
  }
};

const setMapHandler = async (config: { url: string; size: Size }) => {
  const size = await getImageSize(window.platform.getResource(config.url));
  const cover = {
    url: config.url,
    ...size,
    proportion: {
      scale: (config.size.width / size.width) * 1000,
      unit: "mm",
    },
  };
  const data = await genTabulationData(tabulationData.value.paperKey, undefined, cover);
  const store = draw.value!.store;
  const img = data.image?.find((item) => item.key === tableCoverKey);
  const text = data.text?.find((item) => item.key === tableCoverScaleKey);

  if (img && text) {
    const sImage = store.getTypeItems("image").find((item) => item.key === tableCoverKey);
    const sText = store
      .getTypeItems("text")
      .find((item) => item.key === tableCoverScaleKey);

    draw.value!.history.onceTrack(() => {
      if (sImage) {
        store.setItem("image", {
          id: sImage.id,
          value: { ...sImage, ...img, id: sImage.id },
        });
      } else {
        store.addItem("image", img);
      }

      if (sText) {
        store.setItem("text", {
          id: text.id,
          value: { ...sText, ...text, id: sText.id },
        });
      } else {
        store.addItem("text", text);
      }
    });
  }
};

// 序号处理
{
  const serialTable = computed(() => {
    const tables = draw.value?.store.getTypeItems("table");
    console.log("update");
    return tables && tables.find((table) => table.key === tableSerialTableKey);
  });

  watchEffect((onCleanup) => {
    if (!draw.value || !serialTable.value) return;
    const un = draw.value.menusFilter.setShapeMenusFilter(
      serialTable.value.id,
      (menu) => [
        { label: ui18n.t("sys.update"), handler: () => updateSerialTable(false) },
        ...menu,
      ]
    );
    onCleanup(un);
  });

  const updateSerialTable = (autoGen = true) => {
    const d = draw.value;
    const overview = overviewData.value?.store.layers.default;
    const serials = overview.serial;
    if (!d) {
      return;
    }
    const pack = autoGen
      ? d.history.preventTrack.bind(d.history)
      : (run: () => void) => run();
    if (!serials?.length) {
      if (serialTable.value) {
        pack(() => {
          d.store.delItem("table", serialTable.value!.id);
        });
      }
      return;
    }
    const table = serialTable.value || addTable(d as any);
    const syncSerials = serials.map((item) => {
      let desc = "";
      if (item.joinIds) {
        const names = item.joinIds
          .map((id) => {
            const img = overview.image?.find((image) => image.id === id)?.name;
            return img || overview.icon?.find((image) => image.id === id)?.name;
          })
          .filter(Boolean);
        desc = names.join("、");
      }
      return {
        ...item,
        hideSerial: false,
        desc,
      };
    });

    // 找出没有关联的痕迹物证
    const images = [...(overview.image || []), ...(overview.icon || [])];
    images?.forEach((image) => {
      if (
        image.key !== "trace" ||
        syncSerials.some((item) => item.joinIds?.includes(image.id))
      )
        return;

      syncSerials.push({
        id: image.id,
        content: getCurrentNdxRaw(syncSerials),
        hideSerial: true,
        desc: image.name || "",
      } as any);
    });

    // 合并相同序号数据
    for (let i = 0; i < syncSerials.length; i++) {
      const self = syncSerials[i];
      for (let j = i + 1; j < syncSerials.length; j++) {
        if (syncSerials[j].content === self.content) {
          if (syncSerials[j].desc && self.desc !== syncSerials[j].desc) {
            self.desc = self.desc + "、" + syncSerials[j].desc;
          }
          syncSerials.splice(j--, 1);
        }
      }
    }

    draw.value?.runHook(() => syncTable(table, syncSerials));

    if (serialTable.value) {
      pack(() => {
        d.store.setItem("table", {
          id: serialTable.value!.id,
          value: serialTable.value!,
        });
      });
    } else {
      table.key = tableSerialTableKey;
      pack(() => {
        d.store.addItem("table", table);
      });
    }
  };

  watch(
    draw,
    (draw) => {
      if (!draw) return;
      if (!serialTable.value) {
        setTimeout(() => updateSerialTable(true), 500);
      }
    },
    { immediate: true }
  );
}

const needScreenshot = ref<false | number>(false);
const coverSetting = computed(() => {
  const cover = draw.value?.store.items.find((item) => item.key === tableCoverKey);
  return cover?.userData as
    | { showScale: boolean; showViewportLabelLine?: boolean; scale: number }
    | undefined;
});

let setOrigin: (canvas: HTMLCanvasElement) => void;
const originConfig = shallowRef<{ size: Size; scale: number }>();
const setCover = (paperKey: PaperKey, draw: Draw) => {
  const cleanups: (() => void)[] = [];
  const cleanup = () => {
    mergeFuns(cleanups)();
    cleanups.length = 0;
  };
  let cover = draw.store.items.find((item) => item.key === tableCoverKey) as ImageData;
  // if (import.meta.env.DEV && cover) {
  //   draw.history.preventTrack(() => {
  //     draw.store.delItem("image", cover!.id);
  //     cover = null as any;
  //   });
  // }
  const { margin, size } = getPaperConfig(
    paperConfigs[paperKey].size,
    paperConfigs[paperKey].scale
  );
  if (!cover) {
    cover = reactive({
      ...getBaseItem(),
      disableCopy: true,
      cornerRadius: 0,
      strokeWidth: 0,
      disableDelete: true,
      key: tableCoverKey,
      disableTransformer: true,
      userData: {
        showViewportLabelLine: true,
        showScale: true,
        scale: 0,
      },
      zIndex: -1,
      width: 0,
      height: 0,
      mat: [1, 0, 0, 1, 0, 0],
      itemName: ui18n.t("cover.itemName"),
    });
    const stopWatch = watch(
      originConfig,
      (config) => {
        if (!config) return;
        const pos = getFixPosition(
          {
            left: config.size.width / 2 + margin[3] + getRealPixel(15, paperKey),
            bottom: -config.size.height / 2 + margin[2] + getRealPixel(15, paperKey),
          },
          config.size,
          size
        );
        const mat = new Transform().translate(pos.x, pos.y).m;
        draw.history.preventTrack(() => {
          draw.store.setItem("image", {
            id: cover.id,
            value: {
              mat: mat,
              userData: {
                ...cover.userData,
                scale: config.scale,
              },
            },
          });
        });
        nextTick(() => stopWatch());
      },
      { flush: "sync", immediate: true }
    );
    cleanups.push(stopWatch);
    draw.store.addItem("image", cover);
  } else {
    delete cover.url;
  }

  let text = draw.store.items.find((item) => item.key === tableCoverScaleKey) as TextData;
  // if (import.meta.env.DEV && text) {
  //   draw.history.preventTrack(() => {
  //     draw.store.delItem("text", text!.id);
  //     text = null as any;
  //   });
  // }
  if (!text) {
    const width = getRealPixel(30, paperKey);
    const heihgt = getRealPixel(4.8, paperKey);
    const pos = getFixPosition(
      {
        right: margin[1] + getRealPixel(40, paperKey),
        top: margin[0] + getRealPixel(45, paperKey),
      },
      { width, height: heihgt },
      size
    );
    text = reactive({
      ...getBaseItem(),
      content: ``,
      width,
      heihgt,
      fontSize: getRealPixel(4, paperKey),
      disableEditText: true,
      key: tableCoverScaleKey,
      disableDelete: true,
      align: "center",
      mat: [1, 0, 0, 1, pos.x, pos.y],
    });
    draw.store.addItem("text", text);
    // let stopWatch = watch(
    //   () => cover.width && cover.height,
    //   (loaded) => {
    //     if (loaded) {
    //       const mat = [...cover.mat];
    //       const x = mat[4] - (text.width || 0) / 2;
    //       const y = mat[5] + cover.height / 2 + getRealPixel(5, paperKey);
    //       mat[4] = x;
    //       mat[5] = y;
    //       draw.history.preventTrack(() => {
    //         draw.store.setItem("text", { id: text.id, value: { mat } });
    //       });
    //       nextTick(() => {
    //         stopWatch();
    //       });
    //     }
    //   }
    // );
    // cleanups.push(stopWatch);
  }
  // 兼容旧数据
  if (!cover.userData) {
    const scale =
      (cover.widthRaw! / cover.width) *
      paperConfigs[paperKey].scale *
      cover.proportion!.scale;
    cover.userData = {
      showScale: true,
      scale: round(scale, 1),
    };
  }

  const coverQue = computed(() => draw.store.getItem("image", cover.id));
  const coverTexQue = computed(() => draw.store.getItem("text", text.id));

  const mountMenus = draw.mountFilter;
  const menusFilter = draw.menusFilter;
  draw.excludeSelection.push(cover.id);
  const scale = ref<number>();

  cleanups.push(
    watch(
      () => coverSetting.value?.scale,
      (v) => (scale.value = v),
      { immediate: true }
    ),
    watch(
      coverSetting,
      (setting) => {
        if (coverTexQue.value) {
          coverTexQue.value.content = setting ? `1:${setting.scale}` : "";
          coverTexQue.value.hide = !setting?.showScale;
        }
      },
      { deep: true }
    ),
    watch(
      coverTexQue,
      (tex, _, cleanup) => {
        if (!tex) return;
        cleanup(
          mountMenus.setShapeMenusFilter(tex.id, (menus) => {
            const newMenus = { ...menus };
            delete newMenus.align;
            delete newMenus.fontStyle;
            return newMenus;
          })
        );
      },
      { immediate: true }
    ),
    menusFilter.setShapeMenusFilter(cover.id, () => []),
    mountMenus.setShapeMenusFilter(cover.id, (menus) => ({
      ...menus,
      scale: {
        type: "fixProportion",
        label: ui18n.t("cover.fixProportion"),
        "layout-type": "row",
        get value() {
          return scale.value;
        },
        set value(val) {
          scale.value = Math.max(val || 0, 1);
        },
        onChange() {
          if (coverSetting.value) {
            coverSetting.value.scale = scale.value!;
          }
        },
        props: { min: 1 },
      },
      showScale: {
        type: "check",
        label: ui18n.t("cover.showProportion"),
        "layout-type": "row",
        get value() {
          return coverSetting.value?.showScale;
        },
        set value(val) {
          if (coverSetting.value) {
            coverSetting.value.showScale = val || false;
          }
        },
        props: {},
      },
      showViewportLabelLine: {
        type: "check",
        label: ui18n.t("tabulation.showLabelLine"),
        "layout-type": "row",
        get value() {
          return coverSetting.value?.showViewportLabelLine;
        },
        set value(val) {
          if (coverSetting.value) {
            coverSetting.value.showViewportLabelLine = val || false;
          }
        },
        props: {},
      },
    })),

    watch(coverQue, (cover) => {
      if (!cover) {
        draw.history.preventTrack(() => {
          draw.store.delItem("text", text.id);
        });
        cleanup();
      }
    }),
    watch(
      originConfig,
      (config, _) => {
        if (coverQue.value) {
          coverQue.value.width = config?.size.width || 0;
          coverQue.value.height = config?.size.height || 0;
        }
      },
      { deep: true, immediate: true }
    )
  );

  setOrigin = (origin) => {
    const stage = draw.stage!;
    const $group = stage.findOne<Group>(`#${cover.id}`);
    const $image = $group?.findOne<Image>(".repShape");
    if (!$group || !$image) return;
    // cover.url = origin!.toDataURL();
    $image.image(origin);
  };
  return cleanup;
};

let clearDraw: (() => void) | undefined;
onUnmounted(() => (clearDraw = undefined));
const dataLoaded = ref(false);
Promise.all([refreshOverviewData(), refreshTabulationData()]).then(
  () => (dataLoaded.value = true)
);

const lowVersionHandler = (_draw: Draw) => {
  // 旧数据处理
  _draw.history.preventTrack(() => {
    _draw.store.getTypeItems("image").forEach((item) => {
      if (item.key === tableCoverKey) {
        _draw.store.setItem("image", {
          value: {
            itemName: undefined,
            disableDelete: false,
          },
          id: item.id,
        });
      }
    });
  });
};

const initDraw = async (_draw: Draw) => {
  if (_draw === draw.value) return;
  clearDraw && clearDraw();
  if (!_draw) return;
  const quitMerges: Array<() => void> = [];

  _draw.config.showCompass = false;
  _draw.config.showGrid = false;
  _draw.config.showLabelLine = false;
  _draw.config.showComponentSize = false;
  _draw.viewer.setScaleRange(0.2, 5);
  const config: any = tabulationData.value.store.config || {};
  const data = tabulationData.value;
  const p = tabulationData.value.paperKey;
  await setMap({ url: data.mapUrl!, size: { width: data.width!, height: data.high! } });
  _draw.store.setStore({
    ...tabulationData.value.store,
    config: {
      ...config,
      compass: {
        rotation: 0,
        ...(config.compass || {}),
        url: "./icons/compass.svg",
      },
      proportion: {
        scale: 1 / getRealPixel(1, p),
        unit: "mm",
      },
      strokeProportion: {
        scale: 1 / getRealPixel(1, p),
        unit: "mm",
      },
    },
  });
  quitMerges.push(tabCustomStyle(p, _draw));
  if (overviewData.value.store?.config?.proportion.scale) {
    _draw.history.preventTrack(() => {
      const quit = setCover(p, _draw);
      quit && quitMerges.push(quit);
    });
  } else {
    lowVersionHandler(_draw);
  }
  quitMerges.concat(
    Object.keys(components).map((type) =>
      _draw.menusFilter.setMenusFilter(type as ShapeType, (items) => {
        return items.filter((item) => item.label !== ui18n.t("sys.hide"));
      })
    )
  );
  clearDraw = () => {
    console.error("clear");
    draw.value = undefined;
    mergeFuns(quitMerges)();
    clearDraw = undefined;
  };
  draw.value = _draw;
};

const compass = computed(
  () => draw.value?.store.items.find((item) => item.key === tableCompassKey) as IconData
);
watch(compass, (compass, _, onCleanup) => {
  if (!compass || !draw.value) return;
  const mountMenus = draw.value.mountFilter;
  const menusFilter = draw.value.menusFilter;
  const quits = [
    menusFilter.setShapeMenusFilter(compass.id, () => []),
    mountMenus.setShapeMenusFilter(compass.id, () => ({
      // ...des,
      rotate: {
        type: "num",
        label: ui18n.t("describes.rotate"),
        default: 0,
        props: {
          min: 0,
          max: 360,
        },
        "layout-type": "column",
        sort: 3,
        get value() {
          return round((new Transform(compass.mat).decompose().rotation + 360) % 360, 1);
        },
        set value(val) {
          const config = new Transform(compass.mat).decompose();
          compass.mat = new Transform()
            .translate(config.x, config.y)
            .scale(config.scaleX, config.scaleY)
            .rotate(MathUtils.degToRad(val)).m;
          nextTick(() => {
            draw.value?.stage!.findOne(`#${compass.id}`)?.fire("bound-change");
          });
        },
      },
    })),
  ];
  onCleanup(mergeFuns(quits));
});

watchEffect((onCleanup) => {
  const d = draw.value;
  if (!d?.stage?.container()) return;

  const dom = d.stage.container();
  onCleanup(
    listener(dom, "dblclick", () => {
      d.shapesStatus.actives.some((item) => {
        const id = item.id();
        if (d.store.getItemById(id)?.key === tableCoverKey) {
          router.push({
            ...router.currentRoute.value,
            name: "overview",
            query: params.value,
          } as any);
        }
      });
    })
  );
});

const title = computed(() => tabulationData.value?.title || ui18n.t("tabulation.name1"));
watchEffect(() => {
  document.title = title.value;
});

window.platform.bus.on("requestError", (res: any) => {
  console.log(res);
});
</script>
