import { Viewer } from "../viewer.ts";
import { computed, ref, watch } from "vue";
import { dragListener, listener, scaleListener } from "../../utils/event.ts";
import {
  globalWatch,
  installGlobalVar,
  useCan,
  useDownKeys,
  useMode,
  useStage,
} from "./use-global-vars.ts";
import { Mode } from "../../constant/mode.ts";
import { mergeFuns } from "../../utils/shared.ts";
import { Transform } from "konva/lib/Util";
import { lineLen } from "@/utils/math.ts";

export const useViewer = installGlobalVar(() => {
  const stage = useStage();
  const viewer = new Viewer();
  const can = useCan()
  const transform = ref(new Transform());

  const init = (dom: HTMLDivElement) => {
    const dragDestroy = dragListener(dom, {
      move: ({ end, prev }) => {
        if (can.viewMode) {
          viewer.movePixel({ x: end.x - prev.x, y: end.y - prev.y }); 
        }
      },
      notPrevent: true,
    });
    const scaleDestroy = scaleListener(dom, (info) => {
      if (can.viewMode) {
        viewer.scalePixel(info.center, info.scale);
      }
    });
    viewer.bus.on("transformChange", (newTransform) => {
      // console.log(newTransform.m)
      transform.value = newTransform;
    });
    transform.value = viewer.transform;
    return mergeFuns(dragDestroy, scaleDestroy);
  };

  return {
    var: {
      transform: transform,
      viewer,
    },
    onDestroy: globalWatch(
      () =>  can.viewMouseReact,
      (can, _, onCleanup) => {
        if (can) {
          const dom = stage.value!.getNode().container();
          onCleanup(init(dom));
        }
      },
      { immediate: true }
    ),
  };
}, Symbol("viewer"));

export const useViewerTransform = installGlobalVar(() => {
  const viewer = useViewer();
  return viewer.transform;
}, Symbol("viewTransform"));

export const useViewerTransformConfig = () => {
  const transform = useViewerTransform();
  return computed(() => transform.value.decompose());
};

export const useViewerInvertTransform = () => {
  const transform = useViewerTransform();
  return computed(() => transform.value.copy().invert());
};

export const useViewerInvertTransformConfig = () => {
  const transform = useViewerInvertTransform();
  return computed(() => transform.value.decompose());
};

export const useUnitTransform = installGlobalVar(() => {
  const transform = useViewerTransform();
  const invTransform = useViewerInvertTransform();

  return {
    getPixel(real: number) {
      return lineLen(
        invTransform.value.point({ x: real, y: 0 }),
        invTransform.value.point({ x: 0, y: 0 })
      );
    },
    getReal(pixel: number) {
      return lineLen(
        transform.value.point({ x: pixel, y: 0 }),
        transform.value.point({ x: 0, y: 0 })
      );
    },
  };
}, Symbol("unitTransform"));

export const useCacheUnitTransform = installGlobalVar(() => {
  const unitTransform = useUnitTransform();
  const transform = useViewerTransform();
  const invTransform = useViewerInvertTransform();
  let pixelCache: Record<string, number> = {};
  let realCache: Record<string, number> = {};
  watch(transform, () => {
    pixelCache = {};
  });
  watch(invTransform, () => {
    realCache = {};
  });

  return {
    getPixel(real: number) {
      if (real in pixelCache) {
        return pixelCache[real];
      } else {
        return (pixelCache[real] = unitTransform.getPixel(real));
      }
    },
    getReal(pixel: number) {
      if (pixel in realCache) {
        return realCache[pixel];
      } else {
        return (pixelCache[pixel] = unitTransform.getReal(pixel));
      }
    },
  };
}, Symbol("cacheUnitTransform"));
