import { DC, EntityShape } from "@/deconstruction";
import {
  computed,
  ref,
  Ref,
  toRaw,
  watch,
  watchEffect,
} from "vue";
import { DrawItem } from "../components";
import { useStore } from "../store";
import { installGlobalVar, useStage } from "./use-global-vars";
import { Layer } from "konva/lib/Layer";
import { useMouseShapeStatus } from "./use-mouse-status";

// const useRefreshCount = installGlobalVar(() => ref(0));
// const useRefresh = () => {
//   useRefreshCount
// }

export const useTempLayer = () => {
  const stage = useStage();
  return computed(() => stage.value?.getNode().find<Layer>("#temp")[0]);
};

export const useFormalLayer = () => {
  const stage = useStage();
  return computed(() => stage.value?.getNode().find<Layer>("#formal")[0]);
};

export const useHelperLayer = () => {
  const stage = useStage();
  return computed(() => stage.value?.getNode().find<Layer>("#helper")[0]);
};

export const useMigrateLayer = (shape: Ref<DC<EntityShape> | undefined>) => {
  const formal = useFormalLayer();
  const zIndexs = useZIndexsManage();
  let rawLayer: Layer;
  let toLayer: Layer;

  const recovery = () => {
    const $shape = shape.value?.getNode();
    if (rawLayer && $shape) {
      $shape.remove();
      rawLayer.add($shape);

      if (import.meta.env.DEV) {
        setTimeout(() => {
          console.log(
            `recovery raw:${rawLayer.id()} ${
              rawLayer.children.length
            } to:${toLayer.id()} ${toLayer.children.length}`
          );
        });
      }

      if (toRaw(formal.value) === toRaw(rawLayer) && zIndexs.get($shape)) {
        zIndexs.refresh();
      }
    }
  };
  const migrate = (to: Layer) => {
    if (!shape.value) throw "shape不存在";
    const $shape = shape.value.getNode();
    rawLayer = $shape.getLayer()!;
    toLayer = to;
    $shape.remove();
    to.add($shape);

    if (import.meta.env.DEV) {
      console.log(
        `migrate raw:${rawLayer.id()} ${
          rawLayer.children.length
        } to:${toLayer.id()} ${toLayer.children.length}`
      );
    }
  };

  return [migrate, recovery] as const;
};

export const useMouseMigrateTempLayer = (
  shape: Ref<DC<EntityShape> | undefined>,
  isMigrate?: Ref<boolean>
) => {
  const tempLayer = useTempLayer();
  const [migrate, recovery] = useMigrateLayer(shape);

  if (!isMigrate) {
    // 鼠标状态改变则迁移图层
    const status = useMouseShapeStatus(shape);
    isMigrate = computed(() => status.value.active || status.value.hover);
  }
  
  watch(
    isMigrate,
    (isMigrate, _, onCleanup) => {
      if (isMigrate && tempLayer.value) {
        migrate(tempLayer.value);
        onCleanup(recovery);
      }
    },
    { flush: "sync" }
  );
};

const useCurrentStaticZIndex = installGlobalVar(
  () => ref(0),
  Symbol("currentStaticZIndex")
);

export const useGetStaticZIndex = () => {
  const current = useCurrentStaticZIndex();
  return (refNum = 1) => {
    let isDestory = false;
    const destroy = () => {
      if (!isDestory) {
        current.value -= refNum;
        isDestory = true;
      }
    };
    const result = new Array(refNum)
      .fill(0)
      .map((_, i) => current.value + i + 1);
    current.value += refNum;
    return [result, destroy] as const;
  };
};

export const useShapeStaticZindex = (shape: Ref<DC<EntityShape> | undefined>) => {
  const getStaticZindex = useGetStaticZIndex()
  watchEffect((onCleanup) => {
    if (shape.value) {
      const [indexs, desIndex] = getStaticZindex()
      shape.value.getNode().zIndex(indexs[0])
      onCleanup(desIndex)
    }
  })
} 

const useZIndexsManage = installGlobalVar(() => {
  const store = useStore();
  const map = ref(new Map<EntityShape, DrawItem>());
  const current = useCurrentStaticZIndex();
  const formal = useFormalLayer();
  const sortItems = computed(() => {
    const items = Array.from(map.value.values());
    return store.getItemsZIndex(items);
  });

  const setZIndexs = () => {
    const shapes = Array.from(map.value.keys());
    const raws = Array.from(map.value.values());
    let start = current.value;
    sortItems.value.forEach((item) => {
      const rawNdx = raws.findIndex((raw) => raw === item);
      const shape = shapes[rawNdx];
      const layer = shape.getLayer();
      if (toRaw(layer) !== toRaw(formal.value)) return -1;
      shape.zIndex(start++);
    });
  };

  watch(() => [sortItems.value, current.value], setZIndexs);

  return {
    set(shape: EntityShape, item: DrawItem) {
      map.value.set(shape, item);
    },
    del(shape: EntityShape) {
      map.value.delete(shape);
    },
    get(shape: EntityShape) {
      return map.value.get(shape);
    },
    refresh: setZIndexs,
  };
}, Symbol("zIndexsManage"));

export const useCurrentZIndex = () => {
  const store = useStore();
  return {
    get max() {
      let cur = Number.MIN_VALUE 
      for (const items of Object.values(store.data)) {
        for (const item of items) {
          if (cur < item.zIndex) {
            cur = item.zIndex
          }
        }
      }
      return cur
    },
    get min() {
      let cur = Number.MAX_VALUE 
      for (const items of Object.values(store.data)) {
        for (const item of items) {
          if (cur > item.zIndex) {
            cur = item.zIndex
          }
        }
      }
      return cur
    },
  }
}

export const useZIndex = (
  shape: Ref<DC<EntityShape> | undefined>,
  atData: Ref<DrawItem>
) => {
  const zIndexs = useZIndexsManage();
  watch(shape, (shape, _, onCleanup) => {
    const $shape = shape?.getNode();
    if ($shape) {
      watchEffect(() => {
        zIndexs.set($shape, atData.value);
      });
      onCleanup(() => {
        zIndexs.del($shape);
      });
    }
  });
};
