let exporterAction;

function exportToDeerEngine() {
  // Build your JSON structure and trigger download
  var json = {
    mesh: {
      hasNormalData: true,
      vertexPositions: [],
      vertexNormals: [],
      indices: [],
    },
  };

  function addVertex(vector) {
    json.mesh.vertexPositions.push({
      x: Math.round((vector[0] / 16) * 256),
      y: Math.round((vector[1] / 16) * 256),
      z: Math.round((vector[2] / 16) * 256),
    });

    return json.mesh.vertexPositions.length - 1;
  }

  function addIndex(indexID) {
    json.mesh.indices.push(indexID);
  }

  function addNormal(normal) {
    json.mesh.vertexNormals.push({
      x: Math.round(normal[0] * 64),
      y: Math.round(normal[1] * 64),
      z: Math.round(normal[2] * 64),
    });
  }

  Mesh.all.forEach((mesh) => {
    function getWorldPosition(v) {
      const mat = mesh.mesh.matrixWorld; // mat4 (THREE.Matrix4)
      const vec = new THREE.Vector3(v[0], v[1], v[2]);
      vec.applyMatrix4(mat);

      // Convert to your engine’s left-handed space: flip Y and Z
      return [vec.x, vec.y, -vec.z];
    }

    for (const fkey in mesh.faces) {
      const face = mesh.faces[fkey];
      var verticesIDs = [];

      for (const vKey of face.vertices) {
        const position = getWorldPosition(mesh.vertices[vKey]);
        verticesIDs.push(addVertex(position));
      }

      // DEER ENGINE IS CLOCK FACE
      //for (var i = 0; i < verticesIDs.length; i++) {
      //  addIndex(verticesIDs[i]);
      //}

      if (verticesIDs.length == 3) {
        addIndex(verticesIDs[0]);
        addIndex(verticesIDs[2]);
        addIndex(verticesIDs[1]);
      } else if (verticesIDs.length == 4) {
        addIndex(verticesIDs[0]);
        addIndex(verticesIDs[2]);
        addIndex(verticesIDs[1]);

        addIndex(verticesIDs[1]);
        addIndex(verticesIDs[2]);
        addIndex(verticesIDs[3]);
      }

      // Normal calulation
      var origin = getWorldPosition(mesh.vertices[face.vertices[0]]);
      var dirBRef = getWorldPosition(mesh.vertices[face.vertices[1]]);
      var dirARef = getWorldPosition(mesh.vertices[face.vertices[2]]);
      var dirA = [0, 0, 0];
      var dirB = [0, 0, 0];
      for (var i = 0; i < 3; i++) {
        dirB[i] = dirARef[i] - origin[i];
        dirA[i] = dirBRef[i] - origin[i];
      }

      var normalDir = [0, 0, 0];
      normalDir[0] = dirB[1] * dirA[2] - dirB[2] * dirA[1];
      normalDir[1] = dirB[2] * dirA[0] - dirB[0] * dirA[2];
      normalDir[2] = dirB[0] * dirA[1] - dirB[1] * dirA[0];

      var normalMagnitude = Math.sqrt(
        normalDir[0] * normalDir[0] +
          normalDir[1] * normalDir[1] +
          normalDir[2] * normalDir[2]
      );

      for (var i = 0; i < 3; i++) {
        normalDir[i] = normalDir[i] / normalMagnitude;
      }

      for (var i = 0; i < verticesIDs.length; i++) {
        addNormal(normalDir);
      }
    }
  });

  const face_corners = {
    north: [5, 4, 7, 6],
    east: [1, 5, 3, 7],
    south: [0, 1, 2, 3],
    west: [4, 0, 6, 2],
    up: [2, 3, 6, 7],
    down: [4, 5, 0, 1],
  };

  Cube.all.forEach((cube) => {
    // Cubes are simpler: they have 6 faces and 8 vertices
    const mat = cube.mesh.matrixWorld;

    function getWorldPosition(v) {
      const vec = new THREE.Vector3(v[0], v[1], v[2]);
      vec.applyMatrix4(mat);
      return [vec.x, vec.y, -vec.z]; // Flip Z to match left-handed
    }

    // cube.from and cube.to define the min and max corners
    const from = cube.from; // [x, y, z]
    const to = cube.to; // [x, y, z]
    const corners = [
      [from[0], from[1], from[2]],
      [to[0], from[1], from[2]],
      [from[0], to[1], from[2]],
      [to[0], to[1], from[2]],
      [from[0], from[1], to[2]],
      [to[0], from[1], to[2]],
      [from[0], to[1], to[2]],
      [to[0], to[1], to[2]],
    ];

    for (var i = 0; i < corners.length; i++) {
      corners[i][0] -= cube.origin[0];
      corners[i][1] -= cube.origin[1];
      corners[i][2] -= cube.origin[2];
    }

    for (const fkey in cube.faces) {
      const face = cube.faces[fkey];
      const verticesIDs = [];

      const corner_indices = face_corners[fkey]; // get the right 4 corner indices
      if (!corner_indices) continue; // just in case

      const face_vertices = corner_indices.map((i) => corners[i]);

      for (const v of face_vertices) {
        const position = getWorldPosition(v);
        verticesIDs.push(addVertex(position));
      }

      if (verticesIDs.length == 4) {
        addIndex(verticesIDs[0]);
        addIndex(verticesIDs[1]);
        addIndex(verticesIDs[2]);

        addIndex(verticesIDs[1]);
        addIndex(verticesIDs[3]);
        addIndex(verticesIDs[2]);
      }

      // Calculate normal like in your mesh code
      var origin = getWorldPosition(face_vertices[0]);
      var dirBRef = getWorldPosition(face_vertices[1]);
      var dirARef = getWorldPosition(face_vertices[2]);
      var dirA = [0, 0, 0];
      var dirB = [0, 0, 0];
      for (var i = 0; i < 3; i++) {
        dirA[i] = dirARef[i] - origin[i];
        dirB[i] = dirBRef[i] - origin[i];
      }

      var normalDir = [0, 0, 0];
      normalDir[0] = dirB[1] * dirA[2] - dirB[2] * dirA[1];
      normalDir[1] = dirB[2] * dirA[0] - dirB[0] * dirA[2];
      normalDir[2] = dirB[0] * dirA[1] - dirB[1] * dirA[0];

      var normalMagnitude = Math.sqrt(
        normalDir[0] * normalDir[0] +
          normalDir[1] * normalDir[1] +
          normalDir[2] * normalDir[2]
      );

      for (var i = 0; i < 3; i++) {
        normalDir[i] = normalDir[i] / normalMagnitude;
      }

      for (var i = 0; i < verticesIDs.length; i++) {
        addNormal(normalDir);
      }
    }
  });

  Blockbench.export({
    type: "DeerMesh",
    extensions: ["dmesh"],
    name: Project.name,
    content: autoStringify(json),
  });

  /* 
    Blockbench.showQuickMessage(
      PathModule.join(folder, Project.name + ".dmesh"),
      10000
    );
    Blockbench.writeFile(PathModule.join(folder, Project.name + ".dmesh"), {
      content: autoStringify(json),
    });*/
}

Plugin.register("deer_engine_exporter", {
  title: "Deer Engine",
  author: "Chewico",
  description: "Utilities to work with Deer Engine",
  icon: "export", // any valid Blockbench icon :contentReference[oaicite:5]{index=5}
  version: "1.0.0",
  variant: "both", // supports desktop & web

  onload() {
    // (1) Create the export action
    exporterAction = new Action("export_deer_engine_json", {
      name: "Export to Deer Engine Mesh Format",
      icon: "export",
      click() {
        //visibleOverridesDialog.show();
        exportToDeerEngine();
      },
    });
    // (2) Add it under File → Export (top position)
    MenuBar.addAction(exporterAction, "file.export.0"); // “export” submenu, index 0 :contentReference[oaicite:6]{index=6}
  },

  onunload() {
    // Remove the action when plugin unloads
    exporterAction.delete();
  },
});
