import { ref, reactive, onMounted } from "vue";
import { useOdontogramStore } from "~/store/apps/medical/odontogram";
import { OdontogramMode } from "~/types/apps/medical/odontogram";
import {
  Polygon,
  AMF,
  COF,
  FIS,
  NVT,
  RCT,
  NON,
  UNE,
  PRE,
  ANO,
  CARIES,
  CFR,
  FMC,
  POC,
  RRX,
  MIS,
  IPX,
  FRM_ACR,
  BRIDGE,
  ARROW_TOP_LEFT,
  ARROW_TOP_RIGHT,
  ARROW_TOP_TURN_LEFT,
  ARROW_TOP_TURN_RIGHT,
  ARROW_BOTTOM_LEFT,
  ARROW_BOTTOM_RIGHT,
  ARROW_BOTTOM_TURN_LEFT,
  ARROW_BOTTOM_TURN_RIGHT,
  HAPUS
} from "./useToothRenderer";

const ODONTOGRAM_MODE_HAPUS = 100;
const ODONTOGRAM_MODE_DEFAULT = 0;
const ODONTOGRAM_MODE_AMF = 1;
const ODONTOGRAM_MODE_COF = 2;
const ODONTOGRAM_MODE_FIS = 3;
const ODONTOGRAM_MODE_NVT = 4;
const ODONTOGRAM_MODE_RCT = 5;
const ODONTOGRAM_MODE_NON = 6;
const ODONTOGRAM_MODE_UNE = 7;
const ODONTOGRAM_MODE_PRE = 8;
const ODONTOGRAM_MODE_ANO = 9;
const ODONTOGRAM_MODE_CARIES = 10;
const ODONTOGRAM_MODE_CFR = 11;
const ODONTOGRAM_MODE_FMC = 12;
const ODONTOGRAM_MODE_POC = 13;
const ODONTOGRAM_MODE_RRX = 14;
const ODONTOGRAM_MODE_MIS = 15;
const ODONTOGRAM_MODE_IPX = 16;
const ODONTOGRAM_MODE_FRM_ACR = 17;
const ODONTOGRAM_MODE_BRIDGE = 18;

// Add arrow modes
const ODONTOGRAM_MODE_ARROW_TOP_LEFT = 19;
const ODONTOGRAM_MODE_ARROW_TOP_RIGHT = 20;
const ODONTOGRAM_MODE_ARROW_TOP_TURN_LEFT = 21;
const ODONTOGRAM_MODE_ARROW_TOP_TURN_RIGHT = 22;
const ODONTOGRAM_MODE_ARROW_BOTTOM_LEFT = 23;
const ODONTOGRAM_MODE_ARROW_BOTTOM_RIGHT = 24;
const ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_LEFT = 25;
const ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_RIGHT = 26;

class Odontogram {
  canvas: HTMLCanvasElement | null = null;
  context: CanvasRenderingContext2D | null = null;
  mode = ODONTOGRAM_MODE_DEFAULT;
  hoverGeoms: any[] = [];
  geometry: Record<string, any[]> = {};
  active_geometry: any = null;
  teeth: Record<string, any> = {};
  background: any = null;

  initialize(canvas: HTMLCanvasElement, width: number, height: number) {
    this.canvas = canvas;
    this.canvas.width = width;
    this.canvas.height = height;
    this.context = canvas.getContext("2d");
    this._drawBackground();
  }

  setMode(mode: number) {
    this.mode = mode;
  }

  redraw() {
    if (!this.context || !this.background) return;

    // Clear canvas and redraw background
    this.context.putImageData(this.background.image, 0, 0);

    // Draw existing geometry
    for (const keyCoord in this.geometry) {
      const geoms = this.geometry[keyCoord];
      if (!geoms) continue;

      // Separate bridge and non-bridge geometries
      const bridgeGeoms = geoms.filter(
        (g) => g && g.mode === ODONTOGRAM_MODE_BRIDGE
      );
      const nonBridgeGeoms = geoms.filter(
        (g) => g && g.mode !== ODONTOGRAM_MODE_BRIDGE
      );

      // Draw non-bridge geometries first
      for (const geom of nonBridgeGeoms) {
        if (geom && typeof geom.render === "function") {
          geom.render(this.context);
        }
      }

      // Draw bridge geometries last (on top)
      for (const geom of bridgeGeoms) {
        if (geom && typeof geom.render === "function") {
          geom.render(this.context);
        }
      }
    }

    // Draw hover geometry
    for (const hoverGeom of this.hoverGeoms) {
      if (hoverGeom && typeof hoverGeom.render === "function") {
        hoverGeom.render(this.context);
      }
    }

    // Draw quadrant dividing lines
    const ctx = this.context;
    ctx.beginPath();
    ctx.lineWidth = 1;
    ctx.strokeStyle = "rgba(0, 0, 0, 0.3)";

    // Vertical dividing line between teeth 14 and 21
    const verticalX =
      55 + // pl - 20px left shift
      ((ctx.canvas.width - (85 + 10 + 5 * 16 + 75)) / 16) * 8 + // half width of 8 teeth
      5 * 8 + // gap_per * 8
      75 / 2; // half gap_bag
    ctx.moveTo(verticalX, 75);
    ctx.lineTo(verticalX, ctx.canvas.height - 75);

    // Horizontal dividing line between upper and lower teeth rows
    const horizontalY = 75 + (ctx.canvas.height - 75 - 10) / 2 - 35;
    ctx.moveTo(85, horizontalY);
    ctx.lineTo(ctx.canvas.width - 75, horizontalY);

    ctx.stroke();
  }

  _sideTeeth(
    ctx: CanvasRenderingContext2D,
    numbers: string[],
    bigBoxSize: number,
    smallBoxSize: number,
    xpos: number,
    ypos: number,
    options: { numberPosition?: "above" | "below" } = {}
  ) {
    const offsetX = (options as any).offsetX || 0;
    const offsetY = (options as any).offsetY || 0;
    const scale = (options as any).scale || 1;
    const adjXpos = xpos + offsetX;
    const adjYpos = ypos + offsetY;
    const adjBigBoxSize = bigBoxSize * scale;
    const adjSmallBoxSize = smallBoxSize * scale;

    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = "#303030ff";
    ctx.rect(
      adjXpos + adjSmallBoxSize / 2,
      adjYpos + adjSmallBoxSize / 2,
      adjSmallBoxSize,
      adjSmallBoxSize
    );
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(adjXpos, adjYpos);
    ctx.lineTo(adjXpos + adjSmallBoxSize / 2, adjYpos + adjSmallBoxSize / 2);
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(adjXpos + adjBigBoxSize, adjYpos);
    ctx.lineTo(
      adjXpos + adjBigBoxSize - adjSmallBoxSize / 2,
      adjYpos + adjSmallBoxSize / 2
    );
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(adjXpos, adjYpos + adjBigBoxSize);
    ctx.lineTo(
      adjXpos + adjSmallBoxSize / 2,
      adjYpos + adjBigBoxSize - adjSmallBoxSize / 2
    );
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(adjXpos + adjBigBoxSize, adjYpos + adjBigBoxSize);
    ctx.lineTo(
      adjXpos + adjBigBoxSize - adjSmallBoxSize / 2,
      adjYpos + adjBigBoxSize - adjSmallBoxSize / 2
    );
    ctx.stroke();

    const num = numbers.shift();
    ctx.font = `${14 * scale}px Arial Black`;
    ctx.fillStyle = "#303030ff"; // Set text color to black explicitly
    ctx.textBaseline = options.numberPosition === "above" ? "top" : "bottom";
    ctx.textAlign = "center";
    if (num) {
      ctx.fillText(
        num,
        adjXpos + adjBigBoxSize / 2,
        options.numberPosition === "above"
          ? adjYpos - bigBoxSize * 0.2 - 10
          : adjYpos + bigBoxSize * 1.4
      );
    }

    const x1 = adjXpos;
    const y1 = adjYpos;
    const x2 = adjXpos + adjBigBoxSize;
    const y2 = adjYpos + adjBigBoxSize;
    const cx = adjXpos + adjBigBoxSize / 2;
    const cy = adjYpos + adjBigBoxSize / 2;
    const key = `${x1}:${y1};${x2}:${y2};${cx}:${cy}`;

    this.teeth[key] = {
      num: num || "",
      bigBoxSize: adjBigBoxSize,
      smallBoxSize: adjSmallBoxSize,
      x1,
      y1,
      x2,
      y2,
      cx,
      cy,
      top: {
        tl: { x: adjXpos, y: adjYpos },
        tr: { x: adjXpos + adjBigBoxSize, y: adjYpos },
        br: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2,
          y: adjYpos + adjSmallBoxSize / 2
        },
        bl: {
          x: adjXpos + adjSmallBoxSize / 2,
          y: adjYpos + adjSmallBoxSize / 2
        }
      },
      right: {
        tl: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2,
          y: adjYpos + adjSmallBoxSize / 2
        },
        tr: { x: adjXpos + adjBigBoxSize, y: adjYpos },
        br: { x: adjXpos + adjBigBoxSize, y: adjYpos + adjBigBoxSize },
        bl: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize / 2
        }
      },
      bottom: {
        tl: {
          x: adjXpos + adjSmallBoxSize / 2,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize / 2
        },
        tr: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize / 2
        },
        br: { x: adjXpos + adjBigBoxSize, y: adjYpos + adjBigBoxSize },
        bl: { x: adjXpos, y: adjYpos + adjBigBoxSize }
      },
      left: {
        tl: { x: adjXpos, y: adjYpos },
        tr: {
          x: adjXpos + adjSmallBoxSize / 2,
          y: adjYpos + adjSmallBoxSize / 2
        },
        br: {
          x: adjXpos + adjSmallBoxSize / 2,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize / 2
        },
        bl: { x: adjXpos, y: adjYpos + adjBigBoxSize }
      },
      middle: {
        tl: {
          x: adjXpos + adjSmallBoxSize / 2,
          y: adjYpos + adjSmallBoxSize / 2
        },
        tr: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2,
          y: adjYpos + adjSmallBoxSize / 2
        },
        br: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize / 2
        },
        bl: {
          x: adjXpos + adjSmallBoxSize / 2,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize / 2
        }
      }
    };
  }

  _centerTeeth(
    ctx: CanvasRenderingContext2D,
    numbers: string[],
    bigBoxSize: number,
    smallBoxSize: number,
    xpos: number,
    ypos: number,
    options: { numberPosition?: "above" | "below" } = {}
  ) {
    const offsetX = (options as any).offsetX || 0;
    const offsetY = (options as any).offsetY || 0;
    const scale = (options as any).scale || 1;
    const adjXpos = xpos + offsetX;
    const adjYpos = ypos + offsetY;
    const adjBigBoxSize = bigBoxSize * scale;
    const adjSmallBoxSize = smallBoxSize * scale;

    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = "#303030ff";
    ctx.rect(
      adjXpos + adjSmallBoxSize / 2 + 3,
      adjYpos + adjSmallBoxSize - 3,
      adjSmallBoxSize - 6,
      0
    );
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(adjXpos, adjYpos);
    ctx.lineTo(
      adjXpos + adjSmallBoxSize / 2 + 3,
      adjYpos + adjSmallBoxSize - 3
    );
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(adjXpos + adjBigBoxSize, adjYpos);
    ctx.lineTo(
      adjXpos + adjBigBoxSize - adjSmallBoxSize / 2 - 3,
      adjYpos + adjSmallBoxSize - 3
    );
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(adjXpos, adjYpos + adjBigBoxSize);
    ctx.lineTo(
      adjXpos + adjSmallBoxSize / 2 + 3,
      adjYpos + adjBigBoxSize - adjSmallBoxSize - 3
    );
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(adjXpos + adjBigBoxSize, adjYpos + adjBigBoxSize);
    ctx.lineTo(
      adjXpos + adjBigBoxSize - adjSmallBoxSize / 2 - 3,
      adjYpos + adjBigBoxSize - adjSmallBoxSize - 3
    );
    ctx.stroke();

    const num = numbers.shift();
    ctx.font = `${14 * scale}px Arial Black`;
    ctx.fillStyle = "#303030ff"; // Set text color to black explicitly
    ctx.textBaseline = options.numberPosition === "above" ? "top" : "bottom";
    ctx.textAlign = "center";
    if (num) {
      ctx.fillText(
        num,
        adjXpos + adjBigBoxSize / 2,
        options.numberPosition === "above"
          ? adjYpos - bigBoxSize * 0.2 - 10
          : adjYpos + bigBoxSize * 1.4
      );
    }

    const x1 = adjXpos;
    const y1 = adjYpos;
    const x2 = adjXpos + adjBigBoxSize;
    const y2 = adjYpos + adjBigBoxSize;
    const cx = adjXpos + adjBigBoxSize / 2;
    const cy = adjYpos + adjBigBoxSize / 2;
    const key = `${x1}:${y1};${x2}:${y2};${cx}:${cy}`;

    this.teeth[key] = {
      num: num || "",
      bigBoxSize: adjBigBoxSize,
      smallBoxSize: adjSmallBoxSize,
      x1,
      y1,
      x2,
      y2,
      cx,
      cy,
      top: {
        tl: { x: adjXpos + 1, y: adjYpos },
        tr: { x: adjXpos + adjBigBoxSize, y: adjYpos },
        br: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2 - 3,
          y: adjYpos + adjSmallBoxSize - 3
        },
        bl: {
          x: adjXpos + adjSmallBoxSize / 2 + 3,
          y: adjYpos + adjSmallBoxSize - 3
        }
      },
      right: {
        tl: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2 - 2,
          y: adjYpos + adjSmallBoxSize - 3
        },
        tr: { x: adjXpos + adjBigBoxSize, y: adjYpos },
        br: { x: adjXpos + adjBigBoxSize, y: adjYpos + adjBigBoxSize },
        bl: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2 - 2,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize - 3
        }
      },
      bottom: {
        tl: {
          x: adjXpos + adjSmallBoxSize / 2 + 3,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize - 3
        },
        tr: {
          x: adjXpos + adjBigBoxSize - adjSmallBoxSize / 2 - 3,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize - 3
        },
        br: { x: adjXpos + adjBigBoxSize - 1, y: adjYpos + adjBigBoxSize },
        bl: { x: adjXpos + 1, y: adjYpos + adjBigBoxSize }
      },
      left: {
        tl: { x: adjXpos, y: adjYpos },
        tr: {
          x: adjXpos + adjSmallBoxSize / 2 + 2,
          y: adjYpos + adjSmallBoxSize - 3
        },
        br: {
          x: adjXpos + adjSmallBoxSize / 2 + 2,
          y: adjYpos + adjBigBoxSize - adjSmallBoxSize - 3
        },
        bl: { x: adjXpos, y: adjYpos + adjBigBoxSize }
      },
      middle: {
        tl: { x: 0, y: 0 },
        tr: { x: 0, y: 0 },
        br: { x: 0, y: 0 },
        bl: { x: 0, y: 0 }
      }
    };
  }

  _drawBackground() {
    if (!this.context) return;

    const ctx = this.context;
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

    const width = ctx.canvas.width;
    const height = ctx.canvas.height;
    const pl = 85,
      pr = 70,
      pt = 75,
      pb = 10,
      gap_per = 7,
      gap_bag = 75;
    const bigBoxSize = (width - (pl + pr + gap_per * 16 + gap_bag)) / 16;
    const smallBoxSize = bigBoxSize / 2;

    const numbers = [
      "18",
      "17",
      "16",
      "15",
      "14",
      "13",
      "12",
      "11",
      "21",
      "22",
      "23",
      "24",
      "25",
      "26",
      "27",
      "28",
      "55",
      "54",
      "53",
      "52",
      "51",
      "61",
      "62",
      "63",
      "64",
      "65",
      "85",
      "84",
      "83",
      "82",
      "81",
      "71",
      "72",
      "73",
      "74",
      "75",
      "48",
      "47",
      "46",
      "45",
      "44",
      "43",
      "42",
      "41",
      "31",
      "32",
      "33",
      "34",
      "35",
      "36",
      "37",
      "38"
    ];

    let xpos, ypos;
    let sec = 0;

    for (let y = 0; y < 4; y++) {
      sec = 0;
      for (let x = 0; x < 16; x++) {
        if (x % 8 === 0 && x !== 0) sec++;
        if (y % 3 !== 0 && (x < 8 ? (x % 8) - 2 <= 0 : x % 8 >= 5)) continue;

        xpos = x * bigBoxSize + pl + x * gap_per + sec * gap_bag;
        ypos = y * bigBoxSize + pt + pt * y;

        ctx.beginPath();
        ctx.lineWidth = 2;
        ctx.strokeStyle = "#303030ff";
        ctx.rect(xpos, ypos, bigBoxSize, bigBoxSize);
        ctx.stroke();

        // Determine numberPosition for rows 2 and 3 always "below"
        let numberPosition: "above" | "below" = y < 2 ? "above" : "below";

        if (x >= 5 && x <= 10) {
          this._centerTeeth(
            ctx,
            numbers,
            bigBoxSize,
            smallBoxSize,
            xpos,
            ypos,
            {
              numberPosition
            }
          );

          // Swap top and bottom polygons for rows 2 and 3
          if (y >= 2) {
            const x1 = xpos;
            const y1 = ypos;
            const x2 = xpos + bigBoxSize;
            const y2 = ypos + bigBoxSize;
            const cx = xpos + bigBoxSize / 2;
            const cy = ypos + bigBoxSize / 2;
            const key = `${x1}:${y1};${x2}:${y2};${cx}:${cy}`;

            if (this.teeth[key]) {
              const temp = this.teeth[key].top;
              this.teeth[key].top = this.teeth[key].bottom;
              this.teeth[key].bottom = temp;
            }
          }
        } else {
          this._sideTeeth(ctx, numbers, bigBoxSize, smallBoxSize, xpos, ypos, {
            numberPosition
          });

          // Swap top and bottom polygons for rows 2 and 3
          if (y >= 2) {
            const x1 = xpos;
            const y1 = ypos;
            const x2 = xpos + bigBoxSize;
            const y2 = ypos + bigBoxSize;
            const cx = xpos + bigBoxSize / 2;
            const cy = ypos + bigBoxSize / 2;
            const key = `${x1}:${y1};${x2}:${y2};${cx}:${cy}`;

            if (this.teeth[key]) {
              const temp = this.teeth[key].top;
              this.teeth[key].top = this.teeth[key].bottom;
              this.teeth[key].bottom = temp;
            }
          }
        }
      }
    }

    this.background = {
      image: ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height),
      x: 1,
      y: 1,
      w: ctx.canvas.width,
      h: ctx.canvas.height
    };

    // Draw quadrant dividing lines
    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = "#000";

    // Vertical dividing line between teeth 14 and 21
    const verticalX =
      85 + // pl
      ((ctx.canvas.width - (85 + 10 + 5 * 16 + 75)) / 16) * 8 + // half width of 8 teeth
      5 * 8 + // gap_per * 8
      75 / 2; // half gap_bag
    ctx.moveTo(verticalX, 75);
    ctx.lineTo(verticalX, ctx.canvas.height - 10);

    // Horizontal dividing line between upper and lower teeth rows
    const horizontalY = 75 + (ctx.canvas.height - 75 - 10) / 2;
    ctx.moveTo(0, horizontalY);
    ctx.lineTo(ctx.canvas.width, horizontalY);

    ctx.stroke();

    this.redraw();
  }
}

// Composable
const odontogramInstance = ref<Odontogram | null>(null);
const canvas = ref<HTMLCanvasElement | null>(null);
const mode = ref(ODONTOGRAM_MODE_DEFAULT);
const geometry = reactive<Record<string, any[]>>({});
const width = ref(1500);
const height = ref(675);

function initialize(
  canvasElement: HTMLCanvasElement,
  w: number = 1500,
  h: number = 675
) {
  // width.value = w;
  // height.value = h;
  canvas.value = canvasElement;

  const instance = new Odontogram();
  instance.initialize(canvasElement, w, h);
  odontogramInstance.value = instance;

  // Sync geometry
  Object.assign(geometry, instance.geometry);
}

function downloadImage(callback?: (dataUrl: string) => void) {
  if (!odontogramInstance.value || !odontogramInstance.value.canvas) return;

  const dataUrl = odontogramInstance.value.canvas.toDataURL();
  if (callback) {
    callback(dataUrl);
  } else {
    const link = document.createElement("a");
    link.download = "odontogram.png";
    link.href = dataUrl;
    link.click();
  }
}

export function convertGeom(geom: any, mode: number): any {
  const vertices = geom.vertices || [];
  const options = geom.options || {};

  // Override fillStyle for specific modes to ensure visibility
  let geomObj;
  switch (mode) {
    case ODONTOGRAM_MODE_AMF:
      options.fillStyle = "rgba(255, 0, 0, 0.7)";
      geomObj = new AMF(vertices, options);
      break;
    case ODONTOGRAM_MODE_COF:
      options.fillStyle = "rgba(0, 255, 0, 0.7)";
      geomObj = new COF(vertices, options);
      break;
    case ODONTOGRAM_MODE_FIS:
      options.fillStyle = "rgba(255, 0, 255, 0.7)";
      geomObj = new FIS(vertices, options);
      break;
    case ODONTOGRAM_MODE_NVT:
      geomObj = new NVT(vertices, options);
      break;
    case ODONTOGRAM_MODE_RCT:
      geomObj = new RCT(vertices, options);
      break;
    case ODONTOGRAM_MODE_NON:
      geomObj = new NON(vertices, options);
      break;
    case ODONTOGRAM_MODE_UNE:
      geomObj = new UNE(vertices, options);
      break;
    case ODONTOGRAM_MODE_PRE:
      geomObj = new PRE(vertices, options);
      break;
    case ODONTOGRAM_MODE_ANO:
      geomObj = new ANO(vertices, options);
      break;
    case ODONTOGRAM_MODE_CARIES:
      geomObj = new CARIES(vertices, options);
      break;
    case ODONTOGRAM_MODE_CFR:
      geomObj = new CFR(vertices, options);
      break;
    case ODONTOGRAM_MODE_FMC:
      geomObj = new FMC(vertices, options);
      break;
    case ODONTOGRAM_MODE_POC:
      geomObj = new POC(vertices, options);
      break;
    case ODONTOGRAM_MODE_RRX:
      geomObj = new RRX(vertices, options);
      break;
    case ODONTOGRAM_MODE_MIS:
      geomObj = new MIS(vertices, options);
      break;
    case ODONTOGRAM_MODE_IPX:
      geomObj = new IPX(vertices, options);
      break;
    case ODONTOGRAM_MODE_FRM_ACR:
      geomObj = new FRM_ACR(vertices, options);
      break;
    case ODONTOGRAM_MODE_BRIDGE:
      geomObj = new BRIDGE(geom.startVert, geom.endVert, options);
      break;
    case ODONTOGRAM_MODE_ARROW_TOP_LEFT:
      geomObj = new ARROW_TOP_LEFT(vertices, options);
      break;
    case ODONTOGRAM_MODE_ARROW_TOP_RIGHT:
      geomObj = new ARROW_TOP_RIGHT(vertices, options);
      break;
    case ODONTOGRAM_MODE_ARROW_BOTTOM_LEFT:
      geomObj = new ARROW_BOTTOM_LEFT(vertices, options);
      break;
    case ODONTOGRAM_MODE_ARROW_BOTTOM_RIGHT:
      geomObj = new ARROW_BOTTOM_RIGHT(vertices, options);
      break;
    case ODONTOGRAM_MODE_ARROW_TOP_TURN_LEFT:
      geomObj = new ARROW_TOP_TURN_LEFT(vertices, options);
      break;
    case ODONTOGRAM_MODE_ARROW_TOP_TURN_RIGHT:
      geomObj = new ARROW_TOP_TURN_RIGHT(vertices, options);
      break;
    case ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_LEFT:
      geomObj = new ARROW_BOTTOM_TURN_LEFT(vertices, options);
      break;
    case ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_RIGHT:
      geomObj = new ARROW_BOTTOM_TURN_RIGHT(vertices, options);
      break;
    case ODONTOGRAM_MODE_HAPUS:
      geomObj = new HAPUS(vertices, options);
      break;
    default:
      geomObj = new Polygon(vertices, options);
  }
  geomObj.mode = mode;
  // Preserve pos property from input geom, cast to any to avoid TS error
  (geomObj as any).pos = geom.pos;
  return geomObj;
}

function onMouseMove(
  event: MouseEvent,
  emit?: (event: string, data: any) => void
) {
  // console.log("onMouseMove called with mode:", mode.value);
  // if (mode.value === ODONTOGRAM_MODE_IPX) {
  //   console.log("IPX mode detected in onMouseMove");
  // }

  if (!odontogramInstance.value || !odontogramInstance.value.canvas) return;

  const canvas = odontogramInstance.value.canvas;
  const rect = canvas.getBoundingClientRect();

  // Calculate scale factors for X and Y
  const scaleX = canvas.width / rect.width;
  const scaleY = canvas.height / rect.height;

  // Adjust mouse coordinates to canvas internal resolution
  const mouse = {
    x: (event.clientX - rect.left) * scaleX,
    y: (event.clientY - rect.top) * scaleY
  };

  odontogramInstance.value.hoverGeoms = [];

  for (const keyCoord in odontogramInstance.value.teeth) {
    const teeth = odontogramInstance.value.teeth[keyCoord];
    const coord = parseKeyCoord(keyCoord);

    switch (mode.value) {
      case ODONTOGRAM_MODE_DEFAULT:
      case ODONTOGRAM_MODE_AMF:
      case ODONTOGRAM_MODE_COF:
      case ODONTOGRAM_MODE_FIS:
      case ODONTOGRAM_MODE_CARIES:
        if (
          isRectIntersect(coord, {
            x1: mouse.x,
            y1: mouse.y,
            x2: mouse.x,
            y2: mouse.y
          })
        ) {
          const hoverGeoms = getHoverShapeOnTeeth(mouse, teeth);
          const convertedHoverGeoms = hoverGeoms.map((geom) =>
            convertGeom(geom, mode.value)
          );
          odontogramInstance.value.hoverGeoms =
            odontogramInstance.value.hoverGeoms.concat(convertedHoverGeoms);
        }
        break;

      case ODONTOGRAM_MODE_NVT:
      case ODONTOGRAM_MODE_RCT:
      case ODONTOGRAM_MODE_NON:
      case ODONTOGRAM_MODE_UNE:
      case ODONTOGRAM_MODE_PRE:
      case ODONTOGRAM_MODE_ANO:
      case ODONTOGRAM_MODE_CFR:
      case ODONTOGRAM_MODE_FMC:
      case ODONTOGRAM_MODE_POC:
      case ODONTOGRAM_MODE_RRX:
      case ODONTOGRAM_MODE_MIS:
      case ODONTOGRAM_MODE_IPX:
      case ODONTOGRAM_MODE_FRM_ACR:
      case ODONTOGRAM_MODE_HAPUS:
      case ODONTOGRAM_MODE_ARROW_TOP_LEFT:
      case ODONTOGRAM_MODE_ARROW_TOP_RIGHT:
      case ODONTOGRAM_MODE_ARROW_TOP_TURN_LEFT:
      case ODONTOGRAM_MODE_ARROW_TOP_TURN_RIGHT:
      case ODONTOGRAM_MODE_ARROW_BOTTOM_LEFT:
      case ODONTOGRAM_MODE_ARROW_BOTTOM_RIGHT:
      case ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_LEFT:
      case ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_RIGHT:
        if (
          isRectIntersect(coord, {
            x1: mouse.x,
            y1: mouse.y,
            x2: mouse.x,
            y2: mouse.y
          })
        ) {
          // if (mode.value === ODONTOGRAM_MODE_IPX) {
          //   console.log("IPX hover detected on tooth:", teeth.num);
          // }

          // For IPX mode, determine surface from mouse position
          let surfaceOptions = {};
          if (
            mode.value === ODONTOGRAM_MODE_IPX ||
            mode.value === ODONTOGRAM_MODE_FRM_ACR ||
            mode.value === ODONTOGRAM_MODE_ANO ||
            mode.value === ODONTOGRAM_MODE_UNE ||
            mode.value === ODONTOGRAM_MODE_PRE ||
            mode.value === ODONTOGRAM_MODE_NON ||
            mode.value === ODONTOGRAM_MODE_NVT ||
            mode.value === ODONTOGRAM_MODE_RCT
          ) {
            const hoverShapes = getHoverShapeOnTeeth(mouse, teeth);
            if (hoverShapes.length > 0) {
              // Get the first shape's name as surface
              const surfaceName = hoverShapes[0].name.charAt(0).toUpperCase();
              surfaceOptions = { surface: surfaceName };
            }
          }

          // Determine row based on tooth position
          let row = 0;
          if (teeth.num) {
            const toothNum = parseInt(teeth.num);
            if (!isNaN(toothNum)) {
              if (toothNum >= 11 && toothNum <= 18) {
                row = 1; // Upper right
              } else if (toothNum >= 21 && toothNum <= 28) {
                row = 2; // Upper left
              } else if (toothNum >= 31 && toothNum <= 38) {
                row = 4; // Lower left
              } else if (toothNum >= 41 && toothNum <= 48) {
                row = 3; // Lower right
              } else if (toothNum >= 51 && toothNum <= 55) {
                row = 1; // Upper right (deciduous)
              } else if (toothNum >= 61 && toothNum <= 65) {
                row = 2; // Upper left (deciduous)
              } else if (toothNum >= 71 && toothNum <= 75) {
                row = 4; // Lower left (deciduous)
              } else if (toothNum >= 81 && toothNum <= 85) {
                row = 3; // Lower right (deciduous)
              }
            }
          }

          odontogramInstance.value.hoverGeoms.push(
            convertGeom(
              {
                vertices: [
                  { x: coord.x1, y: coord.y1 },
                  { x: coord.x2, y: coord.y2 }
                ],
                pos: teeth.num,
                options: { ...surfaceOptions, row, pos: teeth.num }
              },
              mode.value
            )
          );
          // Add hover shapes for sub-positions (top, right, bottom, left, middle)
        }
        break;

      case ODONTOGRAM_MODE_BRIDGE:
        if (
          isRectIntersect(coord, {
            x1: mouse.x,
            y1: mouse.y,
            x2: mouse.x,
            y2: mouse.y
          })
        ) {
          // For BRIDGE mode, determine surface from mouse position
          let surfaceOptions = {};
          const hoverShapes = getHoverShapeOnTeeth(mouse, teeth);
          if (hoverShapes.length > 0) {
            // Get the first shape's name as surface
            const surfaceName = hoverShapes[0].name.charAt(0).toUpperCase();
            surfaceOptions = { surface: surfaceName };
          }

          // Determine row based on tooth position
          let row = 0;
          if (teeth.num) {
            const toothNum = parseInt(teeth.num);
            if (!isNaN(toothNum)) {
              if (toothNum >= 11 && toothNum <= 18) {
                row = 1; // Upper right
              } else if (toothNum >= 21 && toothNum <= 28) {
                row = 2; // Upper left
              } else if (toothNum >= 31 && toothNum <= 38) {
                row = 4; // Lower left
              } else if (toothNum >= 41 && toothNum <= 48) {
                row = 3; // Lower right
              } else if (toothNum >= 51 && toothNum <= 55) {
                row = 1; // Upper right (deciduous)
              } else if (toothNum >= 61 && toothNum <= 65) {
                row = 2; // Upper left (deciduous)
              } else if (toothNum >= 71 && toothNum <= 75) {
                row = 4; // Lower left (deciduous)
              } else if (toothNum >= 81 && toothNum <= 85) {
                row = 3; // Lower right (deciduous)
              }
            }
          }

          const hoverGeoms = [
            { x: coord.x1, y: coord.y1 },
            { x: coord.x2, y: coord.y2 }
          ];
          if (odontogramInstance.value.active_geometry) {
            odontogramInstance.value.hoverGeoms = [
              new BRIDGE(
                odontogramInstance.value.active_geometry.startVert,
                hoverGeoms,
                { ...surfaceOptions, row, pos: teeth.num }
              )
            ];
          } else {
            odontogramInstance.value.hoverGeoms = [
              new BRIDGE(hoverGeoms, hoverGeoms, {
                ...surfaceOptions,
                row,
                pos: teeth.num
              })
            ];
          }
        }
        break;

      default:
        break;
    }
  }

  if (odontogramInstance.value.hoverGeoms.length > 0) {
    odontogramInstance.value.canvas.style.cursor =
      mode.value === ODONTOGRAM_MODE_HAPUS ? "pointer" : "pointer";
    // mode.value === ODONTOGRAM_MODE_HAPUS ? "default" : "default";
  } else {
    odontogramInstance.value.canvas.style.cursor = "default";
  }

  odontogramInstance.value.redraw();
}

function parseKeyCoord(key: string) {
  const keyChunks = key.split(";");
  let x1 = 0,
    y1 = 0,
    x2 = 0,
    y2 = 0,
    cx = 0,
    cy = 0;

  for (let i = 0; i < 3; i++) {
    const temp = keyChunks[i].split(":");
    if (i === 0) {
      x1 = parseFloat(temp[0]);
      y1 = parseFloat(temp[1]);
    } else if (i === 1) {
      x2 = parseFloat(temp[0]);
      y2 = parseFloat(temp[1]);
    } else {
      cx = parseFloat(temp[0]);
      cy = parseFloat(temp[1]);
    }
  }

  return { x1, y1, x2, y2, cx, cy };
}

function isRectIntersect(rectA: any, rectB: any) {
  return (
    rectA.x1 < rectB.x2 &&
    rectA.x2 > rectB.x1 &&
    rectA.y1 < rectB.y2 &&
    rectA.y2 > rectB.y1
  );
}

function getHoverShapeOnTeeth(mouse: any, teeth: any) {
  const geoms = [];
  for (const key in teeth) {
    switch (key) {
      case "middle":
      case "top":
      case "bottom":
      case "left":
      case "right":
        if (isPolyIntersect(teeth[key], mouse)) {
          geoms.push({ name: key, coord: teeth[key] });
        }
        break;
    }
  }

  const polygonOpt = {
    fillStyle: "rgba(55, 55, 55, 0.2)"
  };
  const polygons = [];

  for (let i = 0; i < geoms.length; i++) {
    const vertices = [];
    for (const key in geoms[i].coord) {
      vertices.push(geoms[i].coord[key]);
    }
    const pol = new Polygon(vertices, polygonOpt);
    pol.name = geoms[i].name;
    polygons.push(pol);
  }

  return polygons;
}

function isPolyIntersect(polygon: any, point: any) {
  const { x, y } = point;
  const vertices = Object.values(polygon) as { x: number; y: number }[];
  let intersectCount = 0;

  for (let i = 0; i < vertices.length; i++) {
    const v1 = vertices[i];
    const v2 = vertices[(i + 1) % vertices.length];
    if (v1.y > y !== v2.y > y) {
      const intersectionX = v1.x + ((y - v1.y) * (v2.x - v1.x)) / (v2.y - v1.y);
      if (x < intersectionX) {
        intersectCount++;
      }
    }
  }

  return intersectCount % 2 !== 0;
}

function joinShapeTeeth(geoms1: any, geoms2: any) {
  const geometry = JSON.parse(JSON.stringify(geoms1));
  let geom1, geom2;

  for (const keyCoord in geoms2) {
    geom1 = geoms1[keyCoord];
    geom2 = geoms2[keyCoord];
    if (geom1 == null) {
      geometry[keyCoord] = geom2;
    } else {
      geometry[keyCoord] = _joinShapeTeeth(geom1, geom2);
    }
  }

  return geometry;
}

function _joinShapeTeeth(geoms1: any, geoms2: any) {
  let geometry: any[] = [];
  for (const geom2 of geoms2) {
    geometry = [geom2];
    for (const geom1 of geoms1) {
      switch (true) {
        case geom2 instanceof AMF:
          if (geom1 instanceof AMF || geom1 instanceof RCT)
            geometry.push(geom1);
          break;
        case geom2 instanceof COF:
          if (geom1 instanceof COF || geom1 instanceof RCT)
            geometry.push(geom1);
          break;
        case geom2 instanceof FIS:
          if (geom1 instanceof FIS) geometry.push(geom1);
          break;
        case geom2 instanceof NVT:
          if (geom1 instanceof NVT) geometry.push(geom1);
          break;
        case geom2 instanceof RCT:
          if (
            geom1 instanceof AMF ||
            geom1 instanceof COF ||
            geom1 instanceof POC ||
            geom1 instanceof FMC ||
            geom1 instanceof BRIDGE
          )
            geometry.push(geom1);
          break;
        case geom2 instanceof NON:
          if (geom1 instanceof NON) geometry.push(geom1);
          break;
        case geom2 instanceof UNE:
          if (geom1 instanceof UNE) geometry.push(geom1);
          break;
        case geom2 instanceof PRE:
          if (geom1 instanceof PRE) geometry.push(geom1);
          break;
        case geom2 instanceof ANO:
          if (geom1 instanceof ANO) geometry.push(geom1);
          break;
        case geom2 instanceof CARIES:
          if (geom1 instanceof CARIES) geometry.push(geom1);
          break;
        case geom2 instanceof CFR:
          break;
        case geom2 instanceof FMC:
          if (
            geom1 instanceof RCT ||
            geom1 instanceof MIS ||
            geom1 instanceof BRIDGE
          )
            geometry.push(geom1);
          break;
        case geom2 instanceof POC:
          if (
            geom1 instanceof POC ||
            geom1 instanceof IPX ||
            geom1 instanceof RCT ||
            geom1 instanceof MIS ||
            geom1 instanceof BRIDGE
          )
            geometry.push(geom1);
          break;
        case geom2 instanceof RRX:
          break;
        case geom2 instanceof MIS:
          if (
            geom1 instanceof POC ||
            geom1 instanceof FMC ||
            geom1 instanceof FRM_ACR ||
            geom1 instanceof BRIDGE
          )
            geometry.push(geom1);
          break;
        case geom2 instanceof IPX:
          if (geom1 instanceof POC || geom1 instanceof BRIDGE)
            geometry.push(geom1);
          break;
        case geom2 instanceof FRM_ACR:
          if (geom1 instanceof MIS || geom1 instanceof BRIDGE)
            geometry.push(geom1);
          break;
        case geom2 instanceof BRIDGE:
          if (
            geom1 instanceof POC ||
            geom1 instanceof FMC ||
            geom1 instanceof FRM_ACR ||
            geom1 instanceof RCT ||
            geom1 instanceof MIS ||
            geom1 instanceof IPX
          )
            geometry.push(geom1);
          break;
        default:
          console.log("DEFAULT[POLYGON]");
          break;
      }
    }
  }
  return geometry;
}

export function useOdontogram() {
  const store = useOdontogramStore();

  // Helper function to get all teeth keys in bridge range
  function getTeethKeysInRange(startVert: any[], endVert: any[]) {
    if (!odontogramInstance.value) return [];
    const teethKeys = Object.keys(odontogramInstance.value.teeth);
    teethKeys.sort((a, b) => {
      const aCoord = parseKeyCoord(a);
      const bCoord = parseKeyCoord(b);
      return aCoord.x1 - bCoord.x1;
    });

    const startIndex = teethKeys.findIndex((key) => {
      const coord = parseKeyCoord(key);
      return (
        coord.x1 === startVert[0].x &&
        coord.y1 === startVert[0].y &&
        coord.x2 === startVert[1].x &&
        coord.y2 === startVert[1].y
      );
    });
    const endIndex = teethKeys.findIndex((key) => {
      const coord = parseKeyCoord(key);
      return (
        coord.x1 === endVert[0].x &&
        coord.y1 === endVert[0].y &&
        coord.x2 === endVert[1].x &&
        coord.y2 === endVert[1].y
      );
    });

    if (startIndex === -1 || endIndex === -1) return [];

    return startIndex < endIndex
      ? teethKeys.slice(startIndex, endIndex + 1)
      : teethKeys.slice(endIndex, startIndex + 1);
  }

  // Sync store conditions to odontogramInstance geometry and redraw
  function syncGeometryFromStore() {
    if (!odontogramInstance.value) return;

    const newGeometry: Record<string, any[]> = {};

    function getPolygonsForSurface(mouse: any, teeth: any, surfaceKey: string) {
      const polygons = [];
      for (const key in teeth) {
        if (key === surfaceKey) {
          const polygonOpt = {
            fillStyle: "rgba(55, 55, 55, 0.2)"
          };
          const vertices = [];
          for (const vertexKey in teeth[key]) {
            vertices.push(teeth[key][vertexKey]);
          }
          const pol = new Polygon(vertices, polygonOpt);
          pol.name = key;
          polygons.push(pol);
        }
      }
      return polygons;
    }

    // Map store conditions to geometry for all modes including bridge
    for (const condition of store.conditions) {
      // Find tooth key by toothNumber
      const toothKey = Object.keys(odontogramInstance.value?.teeth).find(
        (key) =>
          odontogramInstance.value?.teeth[key].num === condition.toothNumber
      );
      if (!toothKey) continue;

      const teeth = odontogramInstance.value.teeth[toothKey];

      // Handle BRIDGE mode separately
      if (condition.mode === ODONTOGRAM_MODE_BRIDGE) {
        // For bridge conditions, we need to find the corresponding start/finish pair
        // and create a single bridge geometry that spans between them

        // Find all bridge conditions with the same group number
        const bridgeGroup = store.conditions.filter(
          (c) =>
            c.mode === ODONTOGRAM_MODE_BRIDGE && c.group === condition.group
        );

        // Need at least two conditions (start and finish) to create a bridge
        if (bridgeGroup.length < 2) continue;

        // Find start and finish conditions in the group
        const startCondition = bridgeGroup.find(
          (c) => c.position && c.position.endsWith("start")
        );
        const finishCondition = bridgeGroup.find(
          (c) => c.position && c.position.endsWith("finish")
        );

        if (!startCondition || !finishCondition) continue;

        // Find tooth keys for start and finish conditions
        const startToothKey = Object.keys(odontogramInstance.value.teeth).find(
          (key) =>
            odontogramInstance.value!.teeth[key].num ===
            startCondition.toothNumber
        );

        const finishToothKey = Object.keys(odontogramInstance.value.teeth).find(
          (key) =>
            odontogramInstance.value!.teeth[key].num ===
            finishCondition.toothNumber
        );

        if (!startToothKey || !finishToothKey) continue;

        // Get teeth objects
        const startTeeth = odontogramInstance.value.teeth[startToothKey];
        const finishTeeth = odontogramInstance.value.teeth[finishToothKey];

        // Determine row based on tooth position
        let row = 0;
        if (teeth.num) {
          const toothNum = parseInt(teeth.num);
          if (!isNaN(toothNum)) {
            if (toothNum >= 11 && toothNum <= 18) {
              row = 1; // Upper right
            } else if (toothNum >= 21 && toothNum <= 28) {
              row = 2; // Upper left
            } else if (toothNum >= 31 && toothNum <= 38) {
              row = 4; // Lower left
            } else if (toothNum >= 41 && toothNum <= 48) {
              row = 3; // Lower right
            } else if (toothNum >= 51 && toothNum <= 55) {
              row = 1; // Upper right (deciduous)
            } else if (toothNum >= 61 && toothNum <= 65) {
              row = 2; // Upper left (deciduous)
            } else if (toothNum >= 71 && toothNum <= 75) {
              row = 4; // Lower left (deciduous)
            } else if (toothNum >= 81 && toothNum <= 85) {
              row = 3; // Lower right (deciduous)
            }
          }
        }

        // Create start and end vertices
        const startVert = [
          { x: startTeeth.x1, y: startTeeth.y1 },
          { x: startTeeth.x2, y: startTeeth.y2 }
        ];

        const endVert = [
          { x: finishTeeth.x1, y: finishTeeth.y1 },
          { x: finishTeeth.x2, y: finishTeeth.y2 }
        ];

        // Create bridge geometry
        const bridgeGeom = convertGeom(
          {
            startVert,
            endVert,
            pos: `bridge-${condition.group}`,
            options: { row, pos: teeth.num }
          },
          ODONTOGRAM_MODE_BRIDGE
        );

        // Assign bridge geometry to both start and finish teeth
        if (!newGeometry[startToothKey]) {
          newGeometry[startToothKey] = [];
        }
        // Only add the bridge geometry once per tooth
        if (
          !newGeometry[startToothKey].some(
            (g) =>
              g.mode === ODONTOGRAM_MODE_BRIDGE &&
              g.pos === `bridge-${condition.group}`
          )
        ) {
          // Insert at the beginning for start tooth key
          newGeometry[startToothKey].unshift(bridgeGeom);
        }

        if (!newGeometry[finishToothKey]) {
          newGeometry[finishToothKey] = [];
        }
        // Only add the bridge geometry once per tooth
        if (
          !newGeometry[finishToothKey].some(
            (g) =>
              g.mode === ODONTOGRAM_MODE_BRIDGE &&
              g.pos === `bridge-${condition.group}`
          )
        ) {
          // Insert at the end for finish tooth key (default push)
          newGeometry[finishToothKey].push(bridgeGeom);
        }

        continue;
      }

      // Determine surface key from condition.surface or from pos if surface missing or invalid
      const surfaceMap: Record<string, string> = {
        T: "top",
        R: "right",
        B: "bottom",
        L: "left",
        M: "middle"
      };

      let surfaceKey = "middle";
      if (
        condition.surface &&
        ["T", "R", "B", "L", "M"].includes(condition.surface)
      ) {
        surfaceKey = surfaceMap[condition.surface];
      } else if (condition.position && typeof condition.position === "string") {
        // Try to infer surface from position string (pos)
        const parts = condition.position.split("-");
        if (parts.length > 1) {
          const surf = parts[1].toUpperCase();
          if (["T", "R", "B", "L", "M"].includes(surf)) {
            surfaceKey = surfaceMap[surf];
          }
        }
      }

      // For AMF, COF, FIS, CARIES, use polygons for surface
      if (
        condition.mode === 1 || // AMF
        condition.mode === 2 || // COF
        condition.mode === 3 || // FIS
        condition.mode === 10 // CARIES
      ) {
        const polygons = getPolygonsForSurface(null, teeth, surfaceKey);
        if (polygons.length > 0) {
          if (!newGeometry[toothKey]) {
            newGeometry[toothKey] = [];
          }
          for (const pol of polygons) {
            pol.pos =
              condition.toothNumber + "-" + pol.name.charAt(0).toUpperCase();
            const geom = convertGeom(pol, condition.mode);
            newGeometry[toothKey].push(geom);
          }
          continue;
        }
      }

      // Determine row based on tooth position (for NVT and RCT modes)
      let row = 0;
      if (teeth.num) {
        const toothNum = parseInt(teeth.num);
        if (!isNaN(toothNum)) {
          if (toothNum >= 11 && toothNum <= 18) {
            row = 1; // Upper right
          } else if (toothNum >= 21 && toothNum <= 28) {
            row = 2; // Upper left
          } else if (toothNum >= 31 && toothNum <= 38) {
            row = 4; // Lower left
          } else if (toothNum >= 41 && toothNum <= 48) {
            row = 3; // Lower right
          } else if (toothNum >= 51 && toothNum <= 55) {
            row = 1; // Upper right (deciduous)
          } else if (toothNum >= 61 && toothNum <= 65) {
            row = 2; // Upper left (deciduous)
          } else if (toothNum >= 71 && toothNum <= 75) {
            row = 4; // Lower left (deciduous)
          } else if (toothNum >= 81 && toothNum <= 85) {
            row = 3; // Lower right (deciduous)
          }
        }
      }

      // Fallback: use tooth rectangle vertices and pos as tooth number with options for row
      const coord = odontogramInstance.value.teeth[toothKey];
      if (!newGeometry[toothKey]) {
        newGeometry[toothKey] = [];
      }
      if (coord) {
        const geom = convertGeom(
          {
            vertices: [
              { x: coord.x1, y: coord.y1 },
              { x: coord.x2, y: coord.y2 }
            ],
            pos: condition.toothNumber,
            options: { row, pos: condition.toothNumber }
          },
          condition.mode
        );
        newGeometry[toothKey].push(geom);
      }
    }

    odontogramInstance.value.geometry = newGeometry;
    odontogramInstance.value.redraw();
  }

  function clearAll() {
    if (odontogramInstance.value) {
      odontogramInstance.value.geometry = {};
      Object.keys(geometry).forEach((key) => {
        delete geometry[key];
      });
      odontogramInstance.value._drawBackground();
    }
    store.clearAllConditions();
  }

  function setMode(newMode: number) {
    mode.value = newMode;
    if (odontogramInstance.value) {
      odontogramInstance.value.setMode(newMode);
    }
    store.setMode(newMode);
  }

  // Watch store conditions and sync geometry on change
  watch(
    () => store.conditions,
    () => {
      syncGeometryFromStore();
    },
    { deep: true, immediate: true }
  );

  // Watch store currentMode and update mode and odontogramInstance mode
  // watch(
  //   () => store.currentMode,
  //   (newMode) => {
  //     setMode(newMode);
  //   },
  //   { immediate: true }
  // );

  function onMouseClick(
    event: MouseEvent,
    emit?: (event: string, data: any) => void
  ) {
    // console.log("onMouseClick called with mode:", mode.value);
    if (!odontogramInstance.value || !odontogramInstance.value.canvas) return;
    if (mode.value === ODONTOGRAM_MODE_DEFAULT) return;

    const canvas = odontogramInstance.value.canvas;
    const rect = canvas.getBoundingClientRect();

    // Calculate scale factors for X and Y
    const scaleX = canvas.width / rect.width;
    const scaleY = canvas.height / rect.height;

    // Adjust mouse coordinates to canvas internal resolution
    const mouse = {
      x: (event.clientX - rect.left) * scaleX,
      y: (event.clientY - rect.top) * scaleY
    };

    const tempGeoms: Record<string, any[]> = {};

    for (const keyCoord in odontogramInstance.value.teeth) {
      const teeth = odontogramInstance.value.teeth[keyCoord];
      const coord = parseKeyCoord(keyCoord);

      // Check if tooth already has MIS or RRX condition, block other mode changes
      const existingGeoms = odontogramInstance.value.geometry[keyCoord] || [];
      const hasMIS = existingGeoms.some((geom: any) => geom instanceof MIS);
      const hasRRX = existingGeoms.some((geom: any) => geom instanceof RRX);

      if (hasRRX) {
        // RRX can only be changed to MIS or HAPUS
        if (
          mode.value !== ODONTOGRAM_MODE_MIS &&
          mode.value !== ODONTOGRAM_MODE_HAPUS
        ) {
          continue; // Skip this tooth, do not apply other modes
        }
      } else if (hasMIS) {
        // MIS can only be changed to HAPUS
        if (mode.value !== ODONTOGRAM_MODE_HAPUS) {
          continue; // Skip this tooth, do not apply other modes
        }
      }

      switch (mode.value) {
        case ODONTOGRAM_MODE_AMF:
        case ODONTOGRAM_MODE_COF:
        case ODONTOGRAM_MODE_FIS:
        case ODONTOGRAM_MODE_CARIES:
          if (
            isRectIntersect(coord, {
              x1: mouse.x,
              y1: mouse.y,
              x2: mouse.x,
              y2: mouse.y
            })
          ) {
            if (!tempGeoms[keyCoord]) {
              tempGeoms[keyCoord] = [];
            }
            // Use getHoverShapeOnTeeth to get sub-position polygons and assign pos accordingly
            const hoverShapes = getHoverShapeOnTeeth(mouse, teeth);
            if (hoverShapes.length > 0) {
              for (const shape of hoverShapes) {
                if (!shape.pos) {
                  shape.pos =
                    teeth.num + "-" + shape.name.charAt(0).toUpperCase();
                }
                tempGeoms[keyCoord].push(convertGeom(shape, mode.value));
              }
            } else {
              // Fallback to tooth number only if no sub-position found
              tempGeoms[keyCoord].push(
                convertGeom(
                  {
                    vertices: [
                      { x: coord.x1, y: coord.y1 },
                      { x: coord.x2, y: coord.y2 }
                    ],
                    pos: teeth.num + "-M" // Default to middle if no sub-position
                  },
                  mode.value
                )
              );
            }
          }
          break;
        case ODONTOGRAM_MODE_NVT:
        case ODONTOGRAM_MODE_RCT:
        case ODONTOGRAM_MODE_NON:
        case ODONTOGRAM_MODE_UNE:
        case ODONTOGRAM_MODE_PRE:
        case ODONTOGRAM_MODE_ANO:
        case ODONTOGRAM_MODE_CFR:
        case ODONTOGRAM_MODE_FMC:
        case ODONTOGRAM_MODE_POC:
        case ODONTOGRAM_MODE_RRX:
        case ODONTOGRAM_MODE_MIS:
        case ODONTOGRAM_MODE_IPX:
        case ODONTOGRAM_MODE_FRM_ACR:
        case ODONTOGRAM_MODE_ARROW_TOP_LEFT:
        case ODONTOGRAM_MODE_ARROW_TOP_RIGHT:
        case ODONTOGRAM_MODE_ARROW_TOP_TURN_LEFT:
        case ODONTOGRAM_MODE_ARROW_TOP_TURN_RIGHT:
        case ODONTOGRAM_MODE_ARROW_BOTTOM_LEFT:
        case ODONTOGRAM_MODE_ARROW_BOTTOM_RIGHT:
        case ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_LEFT:
        case ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_RIGHT:
          if (
            isRectIntersect(coord, {
              x1: mouse.x,
              y1: mouse.y,
              x2: mouse.x,
              y2: mouse.y
            })
          ) {
            if (!tempGeoms[keyCoord]) {
              tempGeoms[keyCoord] = [];
            }

            // For IPX mode, determine surface from mouse position
            let surfaceOptions = {};
            if (
              mode.value === ODONTOGRAM_MODE_IPX ||
              mode.value === ODONTOGRAM_MODE_FRM_ACR ||
              mode.value === ODONTOGRAM_MODE_ANO ||
              mode.value === ODONTOGRAM_MODE_UNE ||
              mode.value === ODONTOGRAM_MODE_PRE ||
              mode.value === ODONTOGRAM_MODE_NON ||
              mode.value === ODONTOGRAM_MODE_NVT ||
              mode.value === ODONTOGRAM_MODE_RCT
            ) {
              const hoverShapes = getHoverShapeOnTeeth(mouse, teeth);
              if (hoverShapes.length > 0) {
                // Get the first shape's name as surface
                const surfaceName = hoverShapes[0].name.charAt(0).toUpperCase();
                surfaceOptions = { surface: surfaceName };
              }
            }

            // Determine row based on tooth position
            let row = 0;
            if (teeth.num) {
              const toothNum = parseInt(teeth.num);
              if (!isNaN(toothNum)) {
                if (toothNum >= 11 && toothNum <= 18) {
                  row = 1; // Upper right
                } else if (toothNum >= 21 && toothNum <= 28) {
                  row = 2; // Upper left
                } else if (toothNum >= 31 && toothNum <= 38) {
                  row = 4; // Lower left
                } else if (toothNum >= 41 && toothNum <= 48) {
                  row = 3; // Lower right
                } else if (toothNum >= 51 && toothNum <= 55) {
                  row = 1; // Upper right (deciduous)
                } else if (toothNum >= 61 && toothNum <= 65) {
                  row = 2; // Upper left (deciduous)
                } else if (toothNum >= 71 && toothNum <= 75) {
                  row = 4; // Lower left (deciduous)
                } else if (toothNum >= 81 && toothNum <= 85) {
                  row = 3; // Lower right (deciduous)
                }
              }
            }

            tempGeoms[keyCoord].push(
              convertGeom(
                {
                  vertices: [
                    { x: coord.x1, y: coord.y1 },
                    { x: coord.x2, y: coord.y2 }
                  ],
                  pos: teeth.num,
                  options: { ...surfaceOptions, row, pos: teeth.num }
                },
                mode.value
              )
            );
          }
          break;

        case ODONTOGRAM_MODE_HAPUS:
          if (
            isRectIntersect(coord, {
              x1: mouse.x,
              y1: mouse.y,
              x2: mouse.x,
              y2: mouse.y
            })
          ) {
            tempGeoms[keyCoord] = [];
          }
          break;

        case ODONTOGRAM_MODE_BRIDGE:
          if (
            isRectIntersect(coord, {
              x1: mouse.x,
              y1: mouse.y,
              x2: mouse.x,
              y2: mouse.y
            })
          ) {
            // For BRIDGE mode, determine surface from mouse position
            let surfaceOptions = {};
            const hoverShapes = getHoverShapeOnTeeth(mouse, teeth);
            if (hoverShapes.length > 0) {
              // Get the first shape's name as surface
              const surfaceName = hoverShapes[0].name.charAt(0).toUpperCase();
              surfaceOptions = { surface: surfaceName };
            }

            // Determine row based on tooth position
            let row = 0;
            if (teeth.num) {
              const toothNum = parseInt(teeth.num);
              if (!isNaN(toothNum)) {
                if (toothNum >= 11 && toothNum <= 18) {
                  row = 1; // Upper right
                } else if (toothNum >= 21 && toothNum <= 28) {
                  row = 2; // Upper left
                } else if (toothNum >= 31 && toothNum <= 38) {
                  row = 4; // Lower left
                } else if (toothNum >= 41 && toothNum <= 48) {
                  row = 3; // Lower right
                } else if (toothNum >= 51 && toothNum <= 55) {
                  row = 1; // Upper right (deciduous)
                } else if (toothNum >= 61 && toothNum <= 65) {
                  row = 2; // Upper left (deciduous)
                } else if (toothNum >= 71 && toothNum <= 75) {
                  row = 4; // Lower left (deciduous)
                } else if (toothNum >= 81 && toothNum <= 85) {
                  row = 3; // Lower right (deciduous)
                }
              }
            }

            if (!tempGeoms[keyCoord]) {
              tempGeoms[keyCoord] = [];
            }
            if (odontogramInstance.value.active_geometry) {
              // Multi-tooth bridge logic
              const startVert =
                odontogramInstance.value.active_geometry.startVert;
              const endVert = [
                { x: coord.x1, y: coord.y1 },
                { x: coord.x2, y: coord.y2 }
              ];

              // Add row info to startVert and endVert for row awareness
              const startRow = Math.floor(startVert[0].y / 150); // Approximate row height
              const endRow = Math.floor(endVert[0].y / 150);

              // Filter teeth keys to only those in the same row as startVert and endVert
              const teethKeys = Object.keys(
                odontogramInstance.value.teeth
              ).filter((key) => {
                const coord = parseKeyCoord(key);
                const row = Math.floor(coord.y1 / 150);
                return row === startRow && row === endRow;
              });

              // Sort keys by x1 coordinate ascending within the row
              teethKeys.sort((a, b) => {
                const aCoord = parseKeyCoord(a);
                const bCoord = parseKeyCoord(b);
                return aCoord.x1 - bCoord.x1;
              });

              // Find indices of start and end teeth within filtered keys
              const startIndex = teethKeys.findIndex((key) => {
                const coord = parseKeyCoord(key);
                return (
                  coord.x1 === startVert[0].x &&
                  coord.y1 === startVert[0].y &&
                  coord.x2 === startVert[1].x &&
                  coord.y2 === startVert[1].y
                );
              });
              const endIndex = teethKeys.findIndex((key) => {
                const coord = parseKeyCoord(key);
                return (
                  coord.x1 === endVert[0].x &&
                  coord.y1 === endVert[0].y &&
                  coord.x2 === endVert[1].x &&
                  coord.y2 === endVert[1].y
                );
              });

              if (startIndex === -1 || endIndex === -1) {
                // Fallback to single bridge if indices not found
                odontogramInstance.value.active_geometry = convertGeom(
                  {
                    startVert,
                    endVert,
                    options: { ...surfaceOptions, row, pos: teeth.num }
                  },
                  mode.value
                );
                tempGeoms[keyCoord].push(
                  odontogramInstance.value.active_geometry
                );
              } else {
                // Get range between start and end indices
                const [from, to] =
                  startIndex < endIndex
                    ? [startIndex, endIndex]
                    : [endIndex, startIndex];

                // Collect vertices for all teeth in range
                const bridgeStartVert = parseKeyCoord(teethKeys[from]);
                const bridgeEndVert = parseKeyCoord(teethKeys[to]);

                odontogramInstance.value.active_geometry = convertGeom(
                  {
                    startVert: [
                      { x: bridgeStartVert.x1, y: bridgeStartVert.y1 },
                      { x: bridgeStartVert.x2, y: bridgeStartVert.y2 }
                    ],
                    endVert: [
                      { x: bridgeEndVert.x1, y: bridgeEndVert.y1 },
                      { x: bridgeEndVert.x2, y: bridgeEndVert.y2 }
                    ],
                    pos: teeth.num, // Set pos to tooth number for bridge geometry
                    options: { ...surfaceOptions, row, pos: teeth.num }
                  },
                  mode.value
                );

                // Clear individual teeth geometries in the range
                for (let i = from; i <= to; i++) {
                  if (!tempGeoms[teethKeys[i]]) {
                    tempGeoms[teethKeys[i]] = [];
                  }
                }

                // Assign the multi-tooth bridge geometry to all teeth in range
                for (let i = from; i <= to; i++) {
                  tempGeoms[teethKeys[i]].push(
                    odontogramInstance.value.active_geometry
                  );
                }
              }

              odontogramInstance.value.active_geometry = null;
            } else {
              odontogramInstance.value.active_geometry = {
                startVert: [
                  { x: coord.x1, y: coord.y1 },
                  { x: coord.x2, y: coord.y2 }
                ]
              };
            }
          }
          break;

        default:
          if (
            isRectIntersect(coord, {
              x1: mouse.x,
              y1: mouse.y,
              x2: mouse.x,
              y2: mouse.y
            })
          ) {
            if (!tempGeoms[keyCoord]) {
              tempGeoms[keyCoord] = [];
            }
            const temp = getHoverShapeOnTeeth(mouse, teeth);
            for (let i = 0; i < temp.length; i++) {
              temp[i].pos =
                teeth.num + "-" + temp[i].name.charAt(0).toUpperCase();
              tempGeoms[keyCoord].push(convertGeom(temp[i], mode.value));
            }
          }
          break;
      }
    }

    if (mode.value === ODONTOGRAM_MODE_HAPUS) {
      for (const keyCoord in tempGeoms) {
        odontogramInstance.value.geometry[keyCoord] = [];
        geometry[keyCoord] = [];
      }
    } else {
      const newGeometry = { ...odontogramInstance.value.geometry };
      for (const key in tempGeoms) {
        // If mode is MIS or RRX, replace all existing geometries on the tooth
        if (
          mode.value === ODONTOGRAM_MODE_MIS ||
          mode.value === ODONTOGRAM_MODE_RRX
        ) {
          newGeometry[key] = tempGeoms[key];
        } else {
          if (newGeometry[key]) {
            newGeometry[key] = [...newGeometry[key], ...tempGeoms[key]];
          } else {
            newGeometry[key] = tempGeoms[key];
          }
        }
        geometry[key] = newGeometry[key];
      }
      odontogramInstance.value.geometry = newGeometry;
    }

    // Emit geometry change event
    if (emit) {
      emit("update:geometry", geometry);
    }

    // Update store conditions based on current geometry
    const newConditions: import("~/types/apps/medical/odontogram").ToothCondition[] =
      [];

    // Collect all bridge geometries separately
    const bridgeGeometries: any[] = [];
    for (const key in odontogramInstance.value.geometry) {
      const geoms = odontogramInstance.value.geometry[key];
      for (const geom of geoms) {
        if (geom && geom.mode === ODONTOGRAM_MODE_BRIDGE) {
          bridgeGeometries.push({ key, geom });
        }
      }
    }

    // Group bridge geometries by distinct startVert and endVert to identify separate bridges
    const groupedBridges: {
      startVert: any[];
      endVert: any[];
      keys: string[];
    }[] = [];
    for (const { key, geom } of bridgeGeometries) {
      let foundGroup = false;
      for (const group of groupedBridges) {
        if (
          JSON.stringify(group.startVert) === JSON.stringify(geom.startVert) &&
          JSON.stringify(group.endVert) === JSON.stringify(geom.endVert)
        ) {
          group.keys.push(key);
          foundGroup = true;
          break;
        }
      }
      if (!foundGroup) {
        groupedBridges.push({
          startVert: geom.startVert,
          endVert: geom.endVert,
          keys: [key]
        });
      }
    }

    // For each bridge group, assign start and finish positions with group numbers
    let groupCounter = 1;
    for (const group of groupedBridges) {
      const keys = group.keys;
      // Sort keys by x1 and y1 coordinate ascending to distinguish rows
      keys.sort((a, b) => {
        const aCoord = parseKeyCoord(a);
        const bCoord = parseKeyCoord(b);
        if (aCoord.y1 !== bCoord.y1) {
          return aCoord.y1 - bCoord.y1;
        }
        return aCoord.x1 - bCoord.x1;
      });

      // Create conditions for start and finish positions with group numbers
      if (keys.length >= 2) {
        // First key (start)
        const startKey = keys[0];
        const startTeeth = odontogramInstance.value.teeth[startKey];
        if (startTeeth) {
          const startToothNumber = startTeeth.num;
          let startPosition = startToothNumber + "-start";

          // Check if this condition already exists
          const startExists = newConditions.some(
            (cond) =>
              cond.toothNumber === startToothNumber &&
              cond.position === startPosition
          );

          if (!startExists) {
            const startCondition = {
              toothNumber: startToothNumber,
              surface: "M" as "T" | "R" | "B" | "L" | "M",
              mode: ODONTOGRAM_MODE_BRIDGE,
              position: startPosition,
              group: groupCounter
            };
            newConditions.push(startCondition);
          }
        }

        // Last key (finish)
        const finishKey = keys[keys.length - 1];
        const finishTeeth = odontogramInstance.value.teeth[finishKey];
        if (finishTeeth) {
          const finishToothNumber = finishTeeth.num;
          let finishPosition = finishToothNumber + "-finish";

          // Check if this condition already exists
          const finishExists = newConditions.some(
            (cond) =>
              cond.toothNumber === finishToothNumber &&
              cond.position === finishPosition
          );

          if (!finishExists) {
            const finishCondition = {
              toothNumber: finishToothNumber,
              surface: "M" as "T" | "R" | "B" | "L" | "M",
              mode: ODONTOGRAM_MODE_BRIDGE,
              position: finishPosition,
              group: groupCounter
            };
            newConditions.push(finishCondition);
          }
        }

        groupCounter++;
      } else if (keys.length === 1) {
        // Single tooth bridge
        const key = keys[0];
        const teeth = odontogramInstance.value.teeth[key];
        if (teeth) {
          const toothNumber = teeth.num;
          let position = toothNumber + "-start"; // Default to start for single tooth

          // Check if this condition already exists
          const exists = newConditions.some(
            (cond) =>
              cond.toothNumber === toothNumber && cond.position === position
          );

          if (!exists) {
            const condition = {
              toothNumber,
              surface: "M" as "T" | "R" | "B" | "L" | "M",
              mode: ODONTOGRAM_MODE_BRIDGE,
              position,
              group: groupCounter
            };
            newConditions.push(condition);
            groupCounter++;
          }

          // Add bridge geometry for single tooth bridge
          if (!geometry[key]) {
            geometry[key] = [];
          }
          const startVert = [
            { x: teeth.x1, y: teeth.y1 },
            { x: teeth.x2, y: teeth.y2 }
          ];
          const endVert = [
            { x: teeth.x1, y: teeth.y1 },
            { x: teeth.x2, y: teeth.y2 }
          ];
          const bridgeGeom = convertGeom(
            {
              startVert,
              endVert,
              pos: toothNumber + "-start"
            },
            ODONTOGRAM_MODE_BRIDGE
          );
          geometry[key].push(bridgeGeom);
        }
      }
    }

    // Add non-bridge geometries as before
    for (const key in odontogramInstance.value.geometry) {
      const geoms = odontogramInstance.value.geometry[key];
      const teeth = odontogramInstance.value.teeth[key];
      if (!teeth) continue;

      for (const geom of geoms) {
        if (!geom || geom.mode === ODONTOGRAM_MODE_BRIDGE) continue;

        const toothNumber = teeth.num;
        let surface: "T" | "R" | "B" | "L" | "M" | undefined = undefined;
        if (geom.pos && typeof geom.pos === "string") {
          const parts = geom.pos.split("-");
          if (parts.length > 1) {
            const surf = parts[1].toUpperCase();
            if (["T", "R", "B", "L", "M"].includes(surf)) {
              surface = surf as "T" | "R" | "B" | "L" | "M";
            }
          } else {
            surface = "M";
          }
        }

        const position = typeof geom.pos === "string" ? geom.pos : "";

        const condition = {
          toothNumber,
          surface,
          mode: geom.mode !== undefined ? geom.mode : mode.value,
          position
        };
        newConditions.push(condition);
      }
    }

    // Additional log to verify all conditions
    // console.log("DEBUG newConditions:", newConditions);

    store.setConditions(newConditions);

    odontogramInstance.value.redraw();
  }

  return {
    odontogramInstance,
    canvas,
    mode,
    geometry,
    width,
    height,
    initialize,
    setMode,
    onMouseMove,
    onMouseClick,
    downloadImage,
    joinShapeTeeth,
    clearAll,
    // Export mode constants
    ODONTOGRAM_MODE_DEFAULT,
    ODONTOGRAM_MODE_AMF,
    ODONTOGRAM_MODE_COF,
    ODONTOGRAM_MODE_FIS,
    ODONTOGRAM_MODE_NVT,
    ODONTOGRAM_MODE_RCT,
    ODONTOGRAM_MODE_NON,
    ODONTOGRAM_MODE_UNE,
    ODONTOGRAM_MODE_PRE,
    ODONTOGRAM_MODE_ANO,
    ODONTOGRAM_MODE_CARIES,
    ODONTOGRAM_MODE_CFR,
    ODONTOGRAM_MODE_FMC,
    ODONTOGRAM_MODE_POC,
    ODONTOGRAM_MODE_RRX,
    ODONTOGRAM_MODE_MIS,
    ODONTOGRAM_MODE_IPX,
    ODONTOGRAM_MODE_FRM_ACR,
    ODONTOGRAM_MODE_BRIDGE,
    ODONTOGRAM_MODE_ARROW_TOP_LEFT,
    ODONTOGRAM_MODE_ARROW_TOP_RIGHT,
    ODONTOGRAM_MODE_ARROW_BOTTOM_LEFT,
    ODONTOGRAM_MODE_ARROW_BOTTOM_RIGHT,
    ODONTOGRAM_MODE_ARROW_TOP_TURN_LEFT,
    ODONTOGRAM_MODE_ARROW_TOP_TURN_RIGHT,
    ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_LEFT,
    ODONTOGRAM_MODE_ARROW_BOTTOM_TURN_RIGHT,
    ODONTOGRAM_MODE_HAPUS
  };
}
