# Deployment Validator - Deployment configuration validation
# Version: 1.0.0
#
# Validates Docker Compose and Kubernetes deployment configurations

let Common = import "common-validator.ncl" in

{
  # Validate Docker Compose version
  validate_compose_version = fun version =>
    Common.validate_one_of ['3.8, '3.9] version,

  # Validate restart policy
  validate_restart_policy = fun policy =>
    Common.validate_one_of ['no, 'always, 'on-failure, 'unless-stopped] policy,

  # Docker Compose configuration validation
  validate_docker_compose = {
    enabled | Bool | default = true,

    version
      | {
        label = "valid version",
        predicate = validate_compose_version
      }
      | default = '3.8,

    project_name
      | String
      | optional,

    env_file
      | String
      | default = ".env",

    profiles
      | Array String
      | default = [],

    extends
      | {
        file | String,
        service | String,
      }
      | optional,
  },

  # Validate Kubernetes namespace
  validate_k8s_namespace = {
    name
      | String
      | {
        label = "valid namespace",
        predicate = fun s =>
          Common.validate_k8s_name s &&
          std.string.length s <= 63
      },

    labels
      | {_: String}
      | default = {},

    annotations
      | {_: String}
      | default = {},
  },

  # Validate Ingress path type
  validate_path_type = fun path_type =>
    Common.validate_one_of ['Prefix, 'Exact, 'ImplementationSpecific] path_type,

  # Validate Ingress rule
  validate_ingress_rule = {
    host
      | String
      | optional,

    http
      | {
        paths
          | Array {
            path | String,
            path_type
              | {
                label = "valid path type",
                predicate = validate_path_type
              }
              | default = 'Prefix,
            backend | {
              service | {
                name | String,
                port | {
                  number | Number | optional,
                  name | String | optional,
                },
              },
            },
          },
      },
  },

  # Validate Ingress configuration
  validate_ingress = {
    enabled | Bool | default = false,

    name
      | String
      | {
        label = "valid name",
        predicate = Common.validate_k8s_name
      }
      | optional,

    class_name
      | String
      | default = "nginx",

    rules
      | Array validate_ingress_rule
      | default = [],

    tls
      | Array {
        hosts | Array String,
        secret_name | String | optional,
      }
      | default = [],

    annotations
      | {_: String}
      | default = {},
  },

  # Validate Service type
  validate_service_type = fun svc_type =>
    Common.validate_one_of ['ClusterIP, 'NodePort, 'LoadBalancer, 'ExternalName] svc_type,

  # Validate Kubernetes Service configuration
  validate_k8s_service = {
    type
      | {
        label = "valid service type",
        predicate = validate_service_type
      }
      | default = 'ClusterIP,

    cluster_ip
      | String
      | optional,

    external_ips
      | Array String
      | default = [],

    load_balancer_ip
      | String
      | optional,

    load_balancer_source_ranges
      | Array String
      | default = [],

    external_traffic_policy
      | [| 'Cluster, 'Local |]
      | optional,

    session_affinity
      | [| 'None, 'ClientIP |]
      | default = 'None,

    annotations
      | {_: String}
      | default = {},
  },

  # Validate deployment strategy type
  validate_strategy_type = fun strategy =>
    Common.validate_one_of ['RollingUpdate, 'Recreate] strategy,

  # Validate deployment strategy
  validate_deployment_strategy = {
    type
      | {
        label = "valid strategy type",
        predicate = validate_strategy_type
      }
      | default = 'RollingUpdate,

    rolling_update
      | {
        max_surge
          | String
          | {
            label = "valid surge",
            predicate = Common.validate_percentage
          }
          | default = "25%",

        max_unavailable
          | String
          | {
            label = "valid unavailable",
            predicate = Common.validate_percentage
          }
          | default = "25%",
      }
      | optional,
  },

  # Validate ConfigMap
  validate_configmap = {
    name
      | String
      | {
        label = "valid name",
        predicate = Common.validate_k8s_name
      },

    data
      | {_: String}
      | default = {},

    binary_data
      | {_: String}
      | default = {},

    from_files
      | Array String
      | default = [],
  },

  # Validate toleration
  validate_toleration = {
    key | String | optional,

    operator
      | [| 'Exists, 'Equal |]
      | default = 'Equal,

    value | String | optional,

    effect
      | [| 'NoSchedule, 'PreferNoSchedule, 'NoExecute |]
      | optional,

    toleration_seconds | Number | optional,
  },

  # Kubernetes configuration validation
  validate_kubernetes = {
    enabled | Bool | default = false,

    namespace
      | String
      | {
        label = "valid namespace",
        predicate = fun s =>
          Common.validate_k8s_name s &&
          std.string.length s <= 63
      }
      | default = "default",

    create_namespace | Bool | default = false,

    namespace_config
      | validate_k8s_namespace
      | optional,

    service
      | validate_k8s_service
      | default = {type = 'ClusterIP},

    ingress
      | validate_ingress
      | default = {enabled = false},

    deployment_strategy
      | validate_deployment_strategy
      | default = {type = 'RollingUpdate},

    hpa
      | {
        enabled | Bool | default = false,
        min_replicas | Number | default = 1,
        max_replicas | Number | default = 10,
        target_cpu_utilization | Number | default = 80,
        target_memory_utilization | Number | optional,
      }
      | default = {enabled = false},

    configmaps
      | Array validate_configmap
      | default = [],

    pod_annotations
      | {_: String}
      | default = {},

    pod_labels
      | {_: String}
      | default = {},

    service_account
      | String
      | optional,

    image_pull_secrets
      | Array String
      | default = [],

    node_selector
      | {_: String}
      | default = {},

    tolerations
      | Array validate_toleration
      | default = [],

    affinity
      | {
        node_affinity | {_: _} | optional,
        pod_affinity | {_: _} | optional,
        pod_anti_affinity | {_: _} | optional,
      }
      | optional,
  },

  # Validate deployment target
  validate_deployment_target = fun target =>
    Common.validate_one_of ['docker, 'kubernetes, 'both] target,

  # Complete deployment configuration validation
  validate_deployment_config = {
    docker_compose
      | validate_docker_compose
      | optional,

    kubernetes
      | validate_kubernetes
      | optional,

    target
      | {
        label = "valid deployment target",
        predicate = validate_deployment_target
      }
      | default = 'docker,
  },
}
