import cornerstoneDICOMImageLoader from "@cornerstonejs/dicom-image-loader";
import {
  getImageTypeSubItemFromDataset,
  extractOrientationFromDataset,
  extractPositionFromDataset,
  extractSpacingFromDataset,
  extractSliceThicknessFromDataset,
} from "@/utils/extractPositioningFromDataset";
import getNumberValues from "@/utils/getNumberValues";
import isNMReconstructable from "@/utils/isNMReconstructable";
function getSpacingBetweenSlices(dataSet) {
  if (dataSet?.elements?.x00180088) {
    return dataSet.floatString("x00180088");
  }
  const pixelMeasuresSequence = dataSet?.elements?.x00289110;
  if (
    pixelMeasuresSequence?.items?.length &&
    pixelMeasuresSequence.items[0]?.dataSet?.elements?.x00180088
  ) {
    return pixelMeasuresSequence.items[0].dataSet.floatString("x00180088");
  }
}
function parseImageId(imageId) {
  // build a url by parsing out the url scheme and frame index from the imageId
  const firstColonIndex = imageId.indexOf(":");

  let url = imageId.substring(firstColonIndex + 1);
  const frameIndex = url.indexOf("frame=");

  let frame;

  if (frameIndex !== -1) {
    const frameStr = url.substr(frameIndex + 6);

    frame = parseInt(frameStr, 10);
    url = url.substr(0, frameIndex - 1);
  }

  return {
    scheme: imageId.substr(0, firstColonIndex),
    url,
    frame,
  };
}

function metaDataProvider(type, imageId) {
  const parsedImageId = parseImageId(imageId);
  const dataSet = cornerstoneDICOMImageLoader.wadouri.dataSetCacheManager.get(
    parsedImageId.url
  );
  if (!dataSet) {
    return;
  }
  if (type === "imagePlaneModule") {
    const frameIndex = parsedImageId.frame !== undefined ? parsedImageId.frame - 1 : undefined;
    // const imageOrientationPatient = extractOrientationFromDataset(dataSet, frameIndex);
    // let imagePositionPatient = extractPositionFromDataset(dataSet, frameIndex);
    // const pixelSpacing = extractSpacingFromDataset(dataSet, frameIndex);
    // const sliceThickness = extractSliceThicknessFromDataset(dataSet, frameIndex);
    const imageOrientationPatient = extractOrientationFromDataset(dataSet);
    let imagePositionPatient = extractPositionFromDataset(dataSet);
    const pixelSpacing = extractSpacingFromDataset(dataSet);
    const sliceThickness = extractSliceThicknessFromDataset(dataSet);
 
    const modality = dataSet.string("x00080060");
    if (
      modality &&
      modality.includes("NM") &&
      parsedImageId.frame !== undefined &&
      parsedImageId.frame > 1
    ) {
      // 坐标堆叠 (位置相同) ：NM 多帧 DICOM 的空间位置 ( imagePositionPatient ) 通常只存在于 Detector Information Sequence 序列的第一个 Item 中。原来的代码在提取位置时，所有帧都被赋予了第一帧的位置。因为所有帧都挤在一个坐标上，3D 引擎无法根据厚度和法向量空间展开它们，导致间距 (Spacing) 为 0
      // 当识别到 NM 多帧图像且属于多帧切片时，通过 RowCosines 与 ColumnCosines 的叉乘计算出切片的 法向量(Normal) ，并结合 帧索引 (frameIndex) 以及 Spacing Between Slices (0018,0088)（层间距） 或者 Slice Thickness (0018,0050)（层厚） ，自动推算补全后续每一帧的 imagePositionPatient 真实三维坐标
      // 
      if (
        imageOrientationPatient &&
        imagePositionPatient &&
        sliceThickness !== undefined
      ) {
        const spacingBetweenSlices = getSpacingBetweenSlices(dataSet);
        const step =
          spacingBetweenSlices !== undefined ? spacingBetweenSlices : sliceThickness;
        const rowCosines = [
          parseFloat(imageOrientationPatient[0]),
          parseFloat(imageOrientationPatient[1]),
          parseFloat(imageOrientationPatient[2]),
        ];
        const columnCosines = [
          parseFloat(imageOrientationPatient[3]),
          parseFloat(imageOrientationPatient[4]),
          parseFloat(imageOrientationPatient[5]),
        ];
        const normal = [
          rowCosines[1] * columnCosines[2] - rowCosines[2] * columnCosines[1],
          rowCosines[2] * columnCosines[0] - rowCosines[0] * columnCosines[2],
          rowCosines[0] * columnCosines[1] - rowCosines[1] * columnCosines[0],
        ];

        const offset = frameIndex * parseFloat(step);

        imagePositionPatient = [
          parseFloat(imagePositionPatient[0]) + normal[0] * offset,
          parseFloat(imagePositionPatient[1]) + normal[1] * offset,
          parseFloat(imagePositionPatient[2]) + normal[2] * offset,
        ];
      }
    }

    // const imageOrientationPatient = getNumberValues(dataSet, 'x00200037', 6);
    // const imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3);
    // const pixelSpacing = extractSpacingFromDataset(dataSet);
    const imagePixelSpacing = getNumberValues(dataSet, "x00181164", 2);

    // let rowCosines = null;

    // let columnCosines = null;

    // if (imageOrientationPatient) {
    //   rowCosines = [
    //     parseFloat(imageOrientationPatient[0]),
    //     parseFloat(imageOrientationPatient[1]),
    //     parseFloat(imageOrientationPatient[2]),
    //   ];
    //   columnCosines = [
    //     parseFloat(imageOrientationPatient[3]),
    //     parseFloat(imageOrientationPatient[4]),
    //     parseFloat(imageOrientationPatient[5]),
    //   ];
    // }
    const estimatedRadiographicMagnificationFactor = getNumberValues(
      dataSet,
      "x00181114",
      2
    );
    let columnPixelSpacing = null;

    let rowPixelSpacing = null;

    if (pixelSpacing) {
      rowPixelSpacing = pixelSpacing[0];
      columnPixelSpacing = pixelSpacing[1];
    } else if (imagePixelSpacing && estimatedRadiographicMagnificationFactor) {
      rowPixelSpacing =
        imagePixelSpacing[0] / estimatedRadiographicMagnificationFactor[0];
      columnPixelSpacing =
        imagePixelSpacing[1] / estimatedRadiographicMagnificationFactor[1];
    } else if (imagePixelSpacing && !estimatedRadiographicMagnificationFactor) {
      rowPixelSpacing = imagePixelSpacing[0];
      columnPixelSpacing = imagePixelSpacing[1];
    }

    let rowCosines = null;

    let columnCosines = null;

    if (imageOrientationPatient) {
      rowCosines = [
        parseFloat(imageOrientationPatient[0]),
        parseFloat(imageOrientationPatient[1]),
        parseFloat(imageOrientationPatient[2]),
      ];
      columnCosines = [
        parseFloat(imageOrientationPatient[3]),
        parseFloat(imageOrientationPatient[4]),
        parseFloat(imageOrientationPatient[5]),
      ];
    }
    return {
      frameOfReferenceUID: dataSet.string("x00200052"),
      rows: dataSet.uint16("x00280010"),
      columns: dataSet.uint16("x00280011"),
      imageOrientationPatient,
      rowCosines,
      columnCosines,
      imagePositionPatient,
      sliceThickness,
      sliceLocation: dataSet.floatString("x00201041"),
      pixelSpacing,
      rowPixelSpacing,
      columnPixelSpacing,
    };
  }
  if (type === "nmMultiframeGeometryModule") {
    const modality = dataSet.string("x00080060");
    const imageSubType = getImageTypeSubItemFromDataset(dataSet, 2);
    return {
      modality,
      imageType: dataSet.string("x00080008"),
      imageSubType,
      imageOrientationPatient: extractOrientationFromDataset(dataSet),
      imagePositionPatient: extractPositionFromDataset(dataSet),
      sliceThickness: extractSliceThicknessFromDataset(dataSet),
      pixelSpacing: extractSpacingFromDataset(dataSet),
      numberOfFrames: dataSet.uint16("x00280008"),
      isNMReconstructable:
        isNMReconstructable(imageSubType) && modality.includes("NM"),
    };
  }
}
export default metaDataProvider;
