import type Point from "../../../geometry/Point.js";
import type ElevationSampler from "../../support/ElevationSampler.js";
import type { AffineTransformations, PrincipalOffsetPoint, RadialDistortionCoefficients, TangentialDistortionCoefficients } from "../types.js";
import type { ConstantElevation } from "../core/ElevationSourceDefinitions.js";

export interface WorldToImageRequiredProperties {
  /** A fixed length array of 6 numbers corresponding to the camera affine values A0, A1, A2, B0, B1, B2. The coefficient of the affine transformation establishes a relationship between the sensor space and image space. The direction is from ground to image. A0, A1, and A2 represent the translation in x direction, while B0, B1, and B2 represent the translation in y direction. Please refer to the [Oriented Imagery table](https://pro.arcgis.com/en/pro-app/latest/help/data/imagery/oriented-imagery-table.htm) for more information on the afffine values. */
  affineTransformations: AffineTransformations;
  /** A Point representing the camera location in world coordinates where the image was captured. */
  cameraLocation: Point;
  /** The row-wise sorted rotation matrix that defines the transformation from image space to map space, specified as an array of nine floating-point values. */
  rotationMatrix: [
      number,
      number,
      number,
      number,
      number,
      number,
      number,
      number,
      number
  ];
}

export interface WorldToImageWithFOVAndImageSize extends WorldToImageRequiredProperties {
  /** The camera's field-of-view in a horizontal direction. The unit is degrees. The valid values range from 0 through 360. */
  horizontalFieldOfView: number;
  /** Height of the image used for world to image transformation, in pixels. This parameter is used if the focal length is not provided. */
  imageHeight: number;
  /** image used for world to image transformation, in pixels. This parameter is used if the focal length is not provided. */
  imageWidth: number;
  /** The camera's field-of-view in the vertical direction. The unit is degrees. The valid values range from 0 through 180. */
  verticalFieldOfView: number;
}

export interface WorldToImageWithFocalLength extends WorldToImageRequiredProperties {
  /** The focal length of the camera lens. The unit can be microns, millimeters, or pixels. This parameter is used if ImageWidth and ImageHeight are not provided. */
  focalLength: number;
}

export interface WorldToImageOptionalProperties {
  /** A fixed length array of 2 numbers specifying the x-coordinate and  y-coordinate of the principal point of the autocollimation. The units must be the same as the unit used for FocalLength. The default value is [0,0]. This is an optional parameter. */
  principalOffsetPoint?: PrincipalOffsetPoint;
  /** The radial distortion is specified as an array of three numbers, indicating [K1,K2,K3] coefficient values. The coupling unit is the same as the unit specified for FocalLength. The default value is [0,0,0]. This is an optional parameter. */
  radialDistortionCoefficients?: RadialDistortionCoefficients;
  /** The tangential distortion is specified as  an array of three numbers, indicating [P1,P2] coefficient values. The coupling unit is the same as the unit used for FocalLength. The default value is [0,0]. This is an optional parameter. */
  tangentialDistortionCoefficients?: TangentialDistortionCoefficients;
}

/**
 * Represents the properties required for transforming world coordinates to image coordinates.
 * For more information on the properties, please refer to the [Oriented Imagery table](https://pro.arcgis.com/en/pro-app/latest/help/data/imagery/oriented-imagery-table.htm).
 */
export type WorldToImageProperties = WorldToImageOptionalProperties
  & (WorldToImageWithFocalLength | WorldToImageWithFOVAndImageSize);

export interface ImageToWorldRequiredProperties extends WorldToImageRequiredProperties {
  /** The height of the ground at the camera's location (specified by cameraLocation), determined by subtracting the camera's height from the absolute z-coordinate of the location. This value can be adjusted as needed. The elevation value should have the same units as that of the cameraLocation's patial reference system (SRS). */
  averageElevation: number;
  /**
   * The camera orientation of the second rotation around the x-axis of the camera. The value is in degrees. The direction of measurement for heading is in positive counterclockwise direction.
   * The CameraPitch is zero degrees when the camera is facing straight down to the ground. The valid range of CameraPitch values is from 0 through 180 degrees. CameraPitch is 180 degrees for a camera facing straight up, and 90 degrees for a camera facing horizontally.
   */
  cameraPitch: number;
  /** The camera orientation of the final rotation around the z-axis of the camera in the positive clockwise direction. The value is in degrees. Valid values range from -90 to 90. */
  cameraRoll: number;
  /** The farthest usable distance of the imagery from the camera position. This value determines the far plane of the visible frustum. The intersection of the frustum far plane with the ground defines the footprint, which is used to determine whether an image is returned when you click the map. The unit is meters. Values must be greater than zero. */
  farDistance: number;
  /** The camera's field-of-view in a horizontal direction. The unit is degrees. The valid values range from 0 through 360. */
  horizontalFieldOfView: number;
  /** The camera's field-of-view in the vertical direction. The unit is degrees. The valid values range from 0 through 180. */
  verticalFieldOfView: number;
}

/**
 * Represents the properties required for transforming image coordinates to world coordinates.
 * For more information on the properties, please refer to the [Oriented Imagery table](https://pro.arcgis.com/en/pro-app/latest/help/data/imagery/oriented-imagery-table.htm).
 */
export type ImageToWorldProperties = ImageToWorldRequiredProperties
  & WorldToImageOptionalProperties
  & (WorldToImageWithFocalLength | WorldToImageWithFOVAndImageSize);

/** Represents the properties required for updating the elevation of the output point. Users can either provide values from an elevationSampler or constantElevation. */
export type UpdateElevationProps = UpdateElevationWithConstant | UpdateElevationWithSampler;

/** Represents the properties required for updating the elevation of the output point with a constant value. */
export interface UpdateElevationWithConstant {
  /** An elevation source. */
  elevationSource: UpdateElevationPropsWithConstantElevationSource;
}

export type UpdateElevationPropsWithConstantElevationSource = Pick<ConstantElevation, "constantElevation">;

/** Represents the properties required for updating the elevation of the output point with an elevation sampler. */
export interface UpdateElevationWithSampler {
  /** A cache of elevation values created from an elevation service used for synchronously querying elevation information for geometries. For more information on creating an elevation sampler, please refer [ElevationSampler](https://developers.arcgis.com/javascript/latest/api-reference/esri-layers-support-ElevationSampler.html). The elevation value should have the same units as that of the cameraLocation's spatial reference system (SRS). */
  elevationSample: ElevationSampler;
}