
import Foundation

/**
 A single-value metrics aggregation that calculates an approximate count of
 distinct values. Values can be extracted either from specific fields in the
 document or generated by a script.

 [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html)
 */
public struct CardinalityAggregation: Aggregation {
    public var aggs: [Aggregation]?
  
    /// :nodoc:
    public static var typeKey = AggregationResponseMap.cardinality
    
    /// :nodoc:
    public var name: String
    
    /// :nodoc:
    public let field: String?
    
    /// :nodoc:
    public let precisionThreshold: Int?
    
    /// :nodoc:
    public let script: Script?
    
    /// :nodoc:
    public let missing: String?
    
    enum CodingKeys: String, CodingKey {
        case field
        case precisionThreshold = "precision_threshold"
        case script
        case missing
        case aggs
    }
    
    /// Create a [cardinality](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html) aggregation
    ///
    /// - Parameters:
    ///   - name: The aggregation name
    ///   - field: The field to perform the aggregation over
    ///   - precisionThreshold: Allows to trade memory for accuracy, and defines a unique count below which counts are expected to be close to accurate
    ///   - script: A script used to calculate the values
    ///   - missing: Defines how documents that are missing a value should be treated
    public init(
        name: String,
        field: String? = nil,
        precisionThreshold: Int? = nil,
        script: Script? = nil,
        missing: String? = nil,
        aggs: [Aggregation]? = nil
        ) {
        self.name = name
        self.field = field
        self.precisionThreshold = precisionThreshold
        self.script = script
        self.missing = missing
        self.aggs = aggs
    }
    
    /// :nodoc:
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: DynamicKey.self)
        var valuesContainer = container.nestedContainer(keyedBy: CodingKeys.self, forKey: DynamicKey(stringValue: type(of: self).typeKey.rawValue)!)
        try valuesContainer.encodeIfPresent(field, forKey: .field)
        try valuesContainer.encodeIfPresent(precisionThreshold, forKey: .precisionThreshold)
        try valuesContainer.encodeIfPresent(script, forKey: .script)
        try valuesContainer.encodeIfPresent(missing, forKey: .missing)
        if aggs != nil {
          if aggs != nil {
          if aggs != nil && aggs!.count > 0 {
          var aggContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: DynamicKey(stringValue: "aggs")!)
          for agg in aggs! {
            try aggContainer.encode(AnyAggregation(agg), forKey: DynamicKey(stringValue: agg.name)!)
          }
        }
      }
        }
    }
}
