import {} from "@iiif/3d-manifesto-dev";
import { IIIFManifest } from "./iiif";

export async function loadIIIFManifest(manifestUrlOrJson) {
  let iiifManifest = new IIIFManifest(manifestUrlOrJson);
  await iiifManifest.loadManifest();
  let modelTarget;
  let filteredAnnos;
  let i = 0;
  iiifManifest.modelUrls = new Array();

  if (iiifManifest.scenes.length > 0) {
    for (const [i, scene] of iiifManifest.scenes.entries()) { //TODO: support multiple scenes const manifestScene = scene;
    //if (!scene) return;
      // Root scene
      const manifestScene = iiifManifest.scenes[i];

      // Add scene BG color
      iiifManifest.scenes[i].background = await manifestScene.getBackgroundColor();

      // Load individual model annotations
      const annos = iiifManifest.annotationsFromScene(manifestScene);

      filteredAnnos = annos.filter((anno) => {
        const body = anno.getBody()[0];
        return (
          anno.getMotivation()?.[0] === "painting" &&
          (body.isSpecificResource || body?.getType() === "model")
        );
      });

      filteredAnnos.forEach((modelAnnotation) => {
        let modelUrl;
        if (modelAnnotation.getBody()[0].isSpecificResource) {
          modelUrl = modelAnnotation.getBody()[0].getSource()?.id;
        } else {
          modelUrl = modelAnnotation.getBody()[0].id;
        }
        modelTarget = modelAnnotation.getTarget();
        if (modelUrl && modelTarget) {
          iiifManifest.modelUrls.push(modelUrl);
        }
      });
    }
  }
  return {
    manifest: iiifManifest.manifest,
    scenes: iiifManifest.scenes,
    annotations: filteredAnnos,
    modelUrls: iiifManifest.modelUrls,
    modelTarget: modelTarget
  };
}

export async function getAnnotations(iiifManifest, objectsConfig) {
  let ind = objectsConfig.index || 0;
  const modelAnnotations = iiifManifest.annotations[ind];
  if (!modelAnnotations) return;

  const target = iiifManifest.annotations?.[ind];

  if (target == null) {
    // handle missing (out-of-range or undefined)
    throw new Error(`No annotation at index ${ind}`);
  }

  // make sure we have an array to map over
  const items = Array.isArray(target) ? target : [target];

  await Promise.all(
    items.map(async (modelAnnotation) => {       
        if (modelAnnotation.getBody()[0].isSpecificResource) {
          let transforms = new Array();

          try {
            const body = modelAnnotation.getBody?.();
            const first = Array.isArray(body) ? body[0] : null;
            transforms = first?.getTransform?.() || [];
          } catch (e) {
            // No transforms present so keep defaults
            //objectsConfig.models[ind].scale = {x: 1, y: 1, z: 1};
            //objectsConfig.models[ind].rotation = {x: 0, y: 0, z: 0};
            //objectsConfig.models[ind].position = {x: 0, y: 0, z: 0};
            //console.log("No transform present in specific resource body");
          }
          // Correct use of async-safe loop
          for (const transform of transforms) {
            if (!transform.isTransform) continue;

            const transformHandlers = [
              {
                key: "isScaleTransform",
                action: () => {
                  const scale = transform.getScale();
                  if (scale) {
                    objectsConfig.models[ind].scale = scale;
                  }
                  else {
                    objectsConfig.models[ind].scale = {x: 1, y: 1, z: 1};
                    console.log("No scale defined in scale transform");
                  }
                },
              },
              {
                key: "isRotateTransform",
                action: () => {
                  const rotation = transform.getRotation();
                  if (rotation) {
                    objectsConfig.models[ind].rotation = rotation;
                  }
                  else { 
                    objectsConfig.models[ind].rotation = {x: 0, y: 0, z: 0};
                    console.log("No rotation defined in rotate transform");
                  }
                },
              },
              {
                key: "isTranslateTransform",
                action: () => {
                  const translation = transform.getTranslation();
                  if (translation) {
                    objectsConfig.models[ind].position = translation;
                  }
                  else { 
                    objectsConfig.models[ind].position = {x: 0, y: 0, z: 0};
                  }
                },
              },
            ];

            for (const { key, action } of transformHandlers) {
              if (transform[key]) {
                action();
              }
            }
          }
        }

        // Position model within target scene if position selector present
        if (iiifManifest.modelTarget.isSpecificResource == true) {
          const selector = iiifManifest.modelTarget.getSelector();
          if (selector && selector.isPointSelector) {
            const position = selector.getLocation();
            if (position) {
              objectsConfig.models[ind].position.x += position.x;
              objectsConfig.models[ind].position.y += position.y;
              objectsConfig.models[ind].position.z += position.z;
            }
          }
        }
        }));
  
  return iiifManifest.annotations;
}
