import type Extent from "../../../geometry/Extent.js";
import type Polygon from "../../../geometry/Polygon.js";
import type RasterInfo from "../../support/RasterInfo.js";
import type { RasterInterpolation } from "../types.js";
import type { WCSVersion } from "./types.js";

/**
 * Coverage information associated with a WCS service. It returns information related to coordinate reference systems, spatial and range domains, and formats supported by a service.
 *
 * @since 4.26
 */
export interface CoverageInfo {
  /** Coverage band names. */
  bandNames: string[];
  /**
   * Coverage
   * description for different versions.
   */
  coverageDescription: CoverageDescriptionV100 | CoverageDescriptionV110 | CoverageDescriptionV201;
  /** Service coverage description. */
  description: string;
  /** Service coverage id. */
  id: string;
  /** Spatial extent of the coverage. */
  lonLatEnvelope?: Extent;
  /** Coverage raster info. */
  rasterInfo: RasterInfo;
  /** Formats supported by a service. */
  supportedFormats: string[];
  /** Interpolation supported by a service. */
  supportedInterpolations?: RasterInterpolation[];
  /** Service coverage title. */
  title: string;
  /** Indicates if the EPSG axis is used. */
  useEPSGAxis: boolean;
  /** The service version. */
  version: WCSVersion;
}

export interface RangeSet {
  /** Provides additional information on compound valued range set. */
  axis: RangeAxis[];
  /** Range set label. */
  label: string;
  /** Range set name. */
  name: string;
  /** The null values is used when valid values are not available. */
  nullValues?: number[] | null;
}

export interface RangeAxis {
  /** Range axis label. */
  label: string;
  /** Range axis name. */
  name: string;
  /** Range axis values. */
  values: string[];
}

export interface DomainSet {
  /** Spatial domain of a coverage. */
  spatialDomain: SpatialDomain;
  /** Temporal domain or extent of a coverage. */
  temporalDomain?: TemporalDomain | null;
}

export interface SpatialDomain {
  /** Spatial domain columns. */
  columns: number;
  /** Spatial domain extent. */
  envelope: Extent;
  /** Spatial domain x, y offset. */
  offset: SpatialDomainOffset;
  /** Spatial domain x, y origin. */
  origin: SpatialDomainOrigin;
  /** Spatial domain rows. */
  rows: number;
}

export interface SpatialDomainOffset {
  /** Spatial domain x offset. */
  x: number;
  /** Spatial domain y offset. */
  y: number;
}

export interface SpatialDomainOrigin {
  /** Spatial domain x origin. */
  x: number;
  /** Spatial domain y origin. */
  y: number;
}

/**
 * Temporal domain or extent of a coverage.
 *
 * @since 4.26
 */
export interface TemporalDomain {
  /** Start date for the temporal domain of a coverage. */
  begin: Date;
  /** End date for the temporal domain of a coverage. */
  end: Date;
  /** The numerical value of the temporal domain or extent. */
  resolution?: number | null;
  /** Temporal units such as day, month, year etc. */
  units?: string | null;
  /** Date values available in the temporal domain. */
  values?: Date[] | null;
}

/**
 * Coverage description for WCS service version 1.0.0.
 *
 * @since 4.26
 */
export interface CoverageDescriptionV100 {
  /** Coverage description. */
  description: string;
  /** Describes the spatial and temporal domain of a coverage. */
  domainSet: DomainSet;
  /** Coverage label. */
  label: string;
  /** Spatial extent of the coverage. */
  lonLatEnvelope: Extent;
  /** Coverage name. */
  name: string;
  /**
   * Defines the properties (categories, measures, or values) assigned to each location in the domain. It can numeric or text values, or
   * it can be a compound values such as income by race, or radiance by wave length. A compound range set may have more than one control parameter or set of “bins”, for
   * quantities related to values of several parameters (such as counts of wildlife tabulated both by size and by species).
   */
  rangeSet: RangeSet[];
  /** Coordinate reference systems supported by a coverage. */
  supportedCRSs: CoverageDescriptionV100SupportedCRSs;
  /** Formats supported by a coverage. */
  supportedFormats: string[];
  /** Interpolations supported by a coverage. */
  supportedInterpolations: string[];
  /** Coverage version. It is always "1.0" for `CoverageDescriptionV100`. */
  readonly version: "1.0";
}

export interface CoverageDescriptionV100SupportedCRSs {
  /** The native coordinate reference system of a coverage – that is, the coordinate reference systems in which coverages can be obtained without any distortion or degradation of the data. */
  nativeCRSs: string[];
  /** Coordinate reference systems in which the coverage can both accept GetCoverage requests and deliver coverage responses. */
  requestResponseCRSs: string[];
}

export interface RangeSetV110 {
  /** Range abstract. */
  abstract?: string | null;
  /** Provides additional information on compound valued range. */
  axis: RangeSetV110Axis[];
  /** Range definition. */
  definition: string;
  /** Range description. */
  description?: string | null;
  /** Range identifier. */
  identifier: string;
  /** Null values. */
  nullValues: number[];
  /** Interpolations supported by the range. */
  supportedInterpolations: string[];
  /** Range title. */
  title?: string | null;
}

export interface RangeSetV110Axis {
  /** The axis bandNoDataValues. */
  bandNoDataValues?: number[];
  /** The axis data type. */
  dataType: string;
  /** The range axis identifier. */
  identifier: string;
  /** The axis unit of measurement. */
  uom: string;
  /** The axis values. */
  values: string[];
}

export interface SpatialDomainV110 extends SpatialDomain {
  /** Specifies spatial resolution of the coordinate reference system. */
  gridBaseCRS: string;
  /** Indicates if the EPSG axis is used. */
  useEPSGAxis: boolean;
}

export interface DomainSetV110 {
  /** Spatial extent or domain of a coverage. */
  spatialDomain: SpatialDomainV110;
  /** Temporal domain or extent of the coverage. */
  temporalDomain: TemporalDomain | null;
}

/**
 * Coverage description for WCS service version 1.1.0.
 *
 * @since 4.26
 */
export interface CoverageDescriptionV110 {
  /** Coverage abstract. */
  abstract: string;
  /** Describes the spatial and temporal domain of a coverage. */
  domain: DomainSetV110;
  /** Coverage identifier. */
  identifier: string;
  /** Coverage metadata. */
  metadata?: string;
  /**
   * Defines the properties (categories, measures, or values) assigned to each location in the domain. It can numeric or text values, or
   * it can be a compound values such as income by race, or radiance by wave length. A compound range set may have more than one control parameter or set of “bins”, for
   * quantities related to values of several parameters (such as counts of wildlife tabulated both by size and by species).
   */
  range: RangeSetV110[];
  /** Resolution x, y. */
  resolution: CoverageDescriptionV110Resolution;
  /** Coordinate reference systems supported by a coverage. */
  supportedCRSs: string[];
  /** Formats supported by a coverage. */
  supportedFormats: string[];
  /** Coverage title. */
  title: string;
  /** Coverage version. It is always "1.1" for `CoverageDescriptionV110`. */
  readonly version: "1.1";
}

export interface CoverageDescriptionV110Resolution {
  /** Resolution x. */
  x: number;
  /** Resolution y. */
  y: number;
}

export interface BoundedByV201 {
  /** The coverage's axis name. */
  axisLabels: string[];
  /** Start date for the temporal extent of a coverage. */
  beginPosition?: Date | null;
  /** End date for the temporal extent of the coverage. */
  endPosition?: Date | null;
  /** The spatial extent of a coverage. */
  envelope: Extent;
  /** The spatial extent dimensions. */
  envelopeAllDims: BoundedByV201EnvelopeAllDims;
  /** Is east first. */
  isEastFirst: boolean;
  /** List of unit of measure (uom) labels for all the axis. */
  uomLabels: string[] | null;
}

export interface BoundedByV201EnvelopeAllDims {
  /** Spatial extent min x and y. */
  maxs: number[];
  /** Spatial extent min x and y. */
  mins: number[];
}

export interface RangeFieldV201 {
  /** Allowed values for the range type. */
  allowedValues?: number[] | null;
  /** Range type description. */
  description?: string | null;
  /** Range type name. */
  name: string;
  /** Number that represents null value. */
  nilValue?: number | null;
  /** Unit of measurement for the range type. */
  uom: string;
}

export interface DomainSetV201 {
  /** Axis labels. */
  axisLabels: string[];
  /** Domain columns of a coverage. */
  columns: number;
  /** Domain grid samples. */
  gridSamples: number[];
  /** Has same axis labels as bounded by. */
  hasSameAxisLabelsAsBoundedBy: boolean;
  /** Domain offset. */
  offset: number[];
  /** Domain origin. */
  origin: number[];
  /** Domain x, y resolution. */
  resolution: DomainSetV201Resolution;
  /** Domain rows of a coverage. */
  rows: number;
}

export interface DomainSetV201Resolution {
  /** Resolution x. */
  x: number;
  /** Resolution.y. */
  y: number;
}

export interface EOCoverageMetadata {
  /** Earth observation. */
  observation: EOCoverageMetadataObservation;
}

export interface EOCoverageMetadataObservation {
  /** Earth observation acquisition type. */
  acquisitionType?: string | null;
  /** Earth observation footprint. */
  footprint?: Polygon | null;
  /** Earth observation identifier. */
  identifier: string;
  /** Earth observation phenomenon time. */
  phenomenonTime?: TemporalDomain | null;
  /** Earth observation resultTime. */
  resultTime?: TemporalDomain | null;
  /** Earth observation status. */
  status?: string | null;
}

/**
 * Coverage description for WCS service version 2.0.1
 *
 * @since 4.26
 */
export interface CoverageDescriptionV201 {
  /** Spatial and temporal extent of a coverage. */
  boundedBy: BoundedByV201;
  /** Coverage function. */
  coverageFunction?: any | null;
  /** Coverage id. */
  coverageId: string;
  /** Domains associated with a coverage. */
  domainSet: DomainSetV201;
  /** The WCS 2.0 Earth Observation coverage metadata. */
  eoMetadata?: EOCoverageMetadata | null;
  /** Coverage extension. */
  extension?: string | null;
  /** Describes the semantics of the range set values supported by a coverage. */
  rangeType: RangeFieldV201[][];
  /** Service x,y resolution. */
  resolution: CoverageDescriptionV201Resolution;
  /** Service parameters. */
  serviceParameters: Record<string, any>;
  /** Service version. */
  readonly version: "2.0";
}

export interface CoverageDescriptionV201Resolution {
  /** Resolution x. */
  x: number;
  /** Resolution y. */
  y: number;
}