import getNumberValues from "./getNumberValues";
import isNMReconstructable from "./isNMReconstructable";

/**
 * Get a subpart of Image Type dicom tag defined by index
 * @param {*} dataSet
 * @param {*} index 0 based index of the subtype
 */
function getImageTypeSubItemFromDataset(dataSet, index) {
  const imageType = dataSet.string("x00080008");

  if (imageType) {
    const subTypes = imageType.split("\\");

    if (subTypes.length > index) {
      return subTypes[index];
    }
  }

  return undefined;
}
// DICOM 标准中针对 Enhanced CT/MR/PET 等“增强型多帧”（Enhanced Multi-frame）影像， 强制要求为每一帧显式记录真实的独立空间坐标 。

// - 它们的数据通常存放在： Per-frame Functional Groups Sequence (5200,9230) -> 对应的 Frame Item -> Plane Position Sequence (0020,9113) -> ImagePositionPatient (0020,0032) 。
function getSharedFunctionalGroupsDataSet(dataSet) {
  const seq = dataSet?.elements?.x52009229;
  if (!seq?.items?.length) {
    return;
  }
  return seq.items[0].dataSet;
}

function getPerFrameFunctionalGroupsDataSet(dataSet, frameIndex) {
  const seq = dataSet?.elements?.x52009230;
  if (!seq?.items?.length) {
    return;
  }
  if (
    !Number.isInteger(frameIndex) ||
    frameIndex < 0 ||
    frameIndex >= seq.items.length
  ) {
    return;
  }
  return seq.items[frameIndex].dataSet;
}

function getOrientationFromPlaneOrientationSequence(dataSet) {
  const seq = dataSet?.elements?.x00209116;
  if (!seq?.items?.length) {
    return;
  }
  return getNumberValues(seq.items[0].dataSet, "x00200037", 6);
}

function getPositionFromPlanePositionSequence(dataSet) {
  const seq = dataSet?.elements?.x00209113;
  if (!seq?.items?.length) {
    return;
  }
  return getNumberValues(seq.items[0].dataSet, "x00200032", 3);
}

function getPixelSpacingFromPixelMeasuresSequence(dataSet) {
  const seq = dataSet?.elements?.x00289110;
  if (!seq?.items?.length) {
    return;
  }
  return getNumberValues(seq.items[0].dataSet, "x00280030", 2);
}

function getSliceThicknessFromPixelMeasuresSequence(dataSet) {
  const seq = dataSet?.elements?.x00289110;
  if (!seq?.items?.length) {
    return;
  }
  if (!seq.items[0]?.dataSet?.elements?.x00180050) {
    return;
  }
  return seq.items[0].dataSet.floatString("x00180050");
}

/**
 * Extracts the orientation from NM multiframe dataset, if image type
 * equal to RECON TOMO or RECON GATED TOMO
 * @param {*} dataSet
 * @returns
 */
function extractOrientationFromNMMultiframeDataset(dataSet) {
  let imageOrientationPatient;
  const modality = dataSet.string("x00080060");

  if (modality?.includes("NM")) {
    const imageSubType = getImageTypeSubItemFromDataset(dataSet, 2);

    if (imageSubType && isNMReconstructable(imageSubType)) {
      if (dataSet.elements.x00540022) {
        imageOrientationPatient = getNumberValues(
          dataSet.elements.x00540022.items[0].dataSet,
          "x00200037",
          6
        );
      }
    }
  }

  return imageOrientationPatient;
}

/**
 * Extracts the position from NM multiframe dataset, if image type
 * equal to RECON TOMO or RECON GATED TOMO
 * @param {*} dataSet
 * @returns
 */
function extractPositionFromNMMultiframeDataset(dataSet) {
  let imagePositionPatient;
  const modality = dataSet.string("x00080060");

  if (modality?.includes("NM")) {
    const imageSubType = getImageTypeSubItemFromDataset(dataSet, 2);

    if (imageSubType && isNMReconstructable(imageSubType)) {
      if (dataSet.elements.x00540022) {
        imagePositionPatient = getNumberValues(
          dataSet.elements.x00540022.items[0].dataSet,
          "x00200032",
          3
        );
      }
    }
  }

  return imagePositionPatient;
}

function isMultiFrame(dataSet) {
  const numberOfFrames =
    dataSet.string("x00280008") || dataSet.uint16("x00280008");
  return numberOfFrames !== undefined && Number(numberOfFrames) > 1;
}

/**
 * Extract orientation information from a dataset. It tries to get the orientation
 * from the Detector Information Sequence (for NM images) if image type equal
 * to RECON TOMO or RECON GATED TOMO
 * @param {*} dataSet
 * @returns
 */
function extractOrientationFromDataset(dataSet) {
  // let imageOrientationPatient;

  // if (isMultiFrame(dataSet)) {
  //   const perFrameDataSet = getPerFrameFunctionalGroupsDataSet(
  //     dataSet,
  //     frameIndex
  //   );
  //   imageOrientationPatient =
  //     getOrientationFromPlaneOrientationSequence(perFrameDataSet);

  //   if (!imageOrientationPatient) {
  //     const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet);
  //     imageOrientationPatient =
  //       getOrientationFromPlaneOrientationSequence(sharedDataSet);
  //   }
  // }

  // if (!imageOrientationPatient) {
  //   imageOrientationPatient = getNumberValues(dataSet, "x00200037", 6);
  // }
  let imageOrientationPatient = getNumberValues(dataSet, "x00200037", 6)
  // Trying to get the orientation from the Plane Orientation Sequence
  if (!imageOrientationPatient && dataSet.elements.x00209116) {
    imageOrientationPatient = getNumberValues(
      dataSet.elements.x00209116.items[0].dataSet,
      "x00200037",
      6
    );
  }

  // If orientation not valid to this point, trying to get the orientation
  // from the Detector Information Sequence (for NM images) with image type
  // equal to RECON TOMO or RECON GATED TOMO

  if (!imageOrientationPatient) {
    imageOrientationPatient =
      extractOrientationFromNMMultiframeDataset(dataSet);
  }

  return imageOrientationPatient;
}

/**
 * Extract position information from a dataset. It tries to get the position
 * from the Detector Information Sequence (for NM images) if image type equal
 * to RECON TOMO or RECON GATED TOMO
 * @param {*} dataSet
 * @returns
 */
function extractPositionFromDataset(dataSet) {
  // let imagePositionPatient;

  // if (isMultiFrame(dataSet)) {
  //   const perFrameDataSet = getPerFrameFunctionalGroupsDataSet(
  //     dataSet,
  //     frameIndex
  //   );
  //   imagePositionPatient =
  //     getPositionFromPlanePositionSequence(perFrameDataSet);

  //   if (!imagePositionPatient) {
  //     const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet);
  //     imagePositionPatient =
  //       getPositionFromPlanePositionSequence(sharedDataSet);
  //   }
  // }

  // if (!imagePositionPatient) {
  //   imagePositionPatient = getNumberValues(dataSet, "x00200032", 3);
  // }
  let imagePositionPatient = getNumberValues(dataSet, 'x00200032', 3);
  // Trying to get the position from the Plane Position Sequence
  if (!imagePositionPatient && dataSet.elements.x00209113) {
    imagePositionPatient = getNumberValues(
      dataSet.elements.x00209113.items[0].dataSet,
      "x00200032",
      3
    );
  }

  // If position not valid to this point, trying to get the position
  // from the Detector Information Sequence (for NM images)
  if (!imagePositionPatient) {
    imagePositionPatient = extractPositionFromNMMultiframeDataset(dataSet);
  }

  return imagePositionPatient;
}

/**
 * Extract the pixelSpacing information. If exists, extracts this information
 * from Pixel Measures Sequence
 * @param {*} dataSet
 * @returns
 */
function extractSpacingFromDataset(dataSet) {
  // let pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);

  // // If pixelSpacing not valid to this point, trying to get the spacing
  // // from the Pixel Measures Sequence
  // if (!pixelSpacing && dataSet.elements.x00289110) {
  //   pixelSpacing = getNumberValues(
  //     dataSet.elements.x00289110.items[0].dataSet,
  //     'x00280030',
  //     2
  //   );
  // }

  // return pixelSpacing;

  let rowPixelSpacing = null;
  let columnPixelSpacing = null;
  // let pixelSpacing;

  // if (isMultiFrame(dataSet)) {
  //   const perFrameDataSet = getPerFrameFunctionalGroupsDataSet(
  //     dataSet,
  //     frameIndex
  //   );
  //   const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet);
  //   pixelSpacing =
  //     getPixelSpacingFromPixelMeasuresSequence(perFrameDataSet) ||
  //     getPixelSpacingFromPixelMeasuresSequence(sharedDataSet);
  // }

  // if (!pixelSpacing) {
  //   pixelSpacing =
  //     getNumberValues(dataSet, "x00280030", 2) ||
  //     getPixelSpacingFromPixelMeasuresSequence(dataSet);
  // }
  let pixelSpacing = getNumberValues(dataSet, 'x00280030', 2);
  const imagePixelSpacing = getNumberValues(dataSet, "x00181164", 2);
  const estimatedRadiographicMagnificationFactor = getNumberValues(
    dataSet,
    "x00181114",
    2
  );
  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];
  }
  return rowPixelSpacing !== null
    ? [rowPixelSpacing, columnPixelSpacing]
    : undefined;
}

/**
 * Extract the sliceThickness information. If exists, extracts this information
 * from Pixel Measures Sequence
 * @param {*} dataSet
 * @returns
 */
function extractSliceThicknessFromDataset(dataSet) {
  let sliceThickness;
  if (dataSet.elements.x00180050) {
      sliceThickness = dataSet.floatString('x00180050');
  }
  else if (dataSet.elements.x00289110 &&
      dataSet.elements.x00289110.items.length &&
      dataSet.elements.x00289110.items[0].dataSet.elements.x00180050) {
      sliceThickness =
          dataSet.elements.x00289110.items[0].dataSet.floatString('x00180050');
  }

  // if (sliceThickness === undefined && isMultiFrame(dataSet)) {
  //   const perFrameDataSet = getPerFrameFunctionalGroupsDataSet(
  //     dataSet,
  //     frameIndex
  //   );
  //   const sharedDataSet = getSharedFunctionalGroupsDataSet(dataSet);
  //   sliceThickness =
  //     getSliceThicknessFromPixelMeasuresSequence(perFrameDataSet) ||
  //     getSliceThicknessFromPixelMeasuresSequence(sharedDataSet);
  // }

  return sliceThickness;
}

export {
  getImageTypeSubItemFromDataset,
  extractOrientationFromDataset,
  extractPositionFromDataset,
  extractSpacingFromDataset,
  extractSliceThicknessFromDataset,
};
