# -*- coding: utf-8 -*- #
# Copyright 2021 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Helpers for flags in commands working with Anthos Multi-Cloud on AWS."""


from googlecloudsdk.api_lib.container.gkemulticloud import util as api_util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.command_lib.util.apis import arg_utils


def AddAwsRegion(parser):
  parser.add_argument(
      '--aws-region', required=True, help='AWS region to deploy the cluster.'
  )


def GetAwsRegion(args):
  return getattr(args, 'aws_region', None)


def AddVpcId(parser):
  parser.add_argument(
      '--vpc-id', required=True, help='VPC associated with the cluster.'
  )


def GetVpcId(args):
  return getattr(args, 'vpc_id', None)


def AddIamInstanceProfile(parser, kind='cluster', required=True):
  """Adds the --iam-instance-profile flag."""
  parser.add_argument(
      '--iam-instance-profile',
      required=required,
      help=(
          'Name or ARN of the IAM instance profile associated with the {}.'
          .format(kind)
      ),
  )


def GetIamInstanceProfile(args):
  return getattr(args, 'iam_instance_profile', None)


def AddInstanceType(parser, kind='control plane'):
  """Adds the --instance-type flag."""
  parser.add_argument(
      '--instance-type',
      help="AWS EC2 instance type for the {}'s nodes.".format(kind),
  )


def GetInstanceType(args):
  return getattr(args, 'instance_type', None)


def AddSpotInstanceTypes(parser, kind='node pool'):
  """Adds the --spot-instance-types flag."""
  parser.add_argument(
      '--spot-instance-types',
      type=arg_parsers.ArgList(),
      metavar='INSTANCE_TYPE',
      help=(
          "List of AWS EC2 instance types for creating a spot {}'s nodes. The"
          ' specified instance types must have the same CPU architecture, the'
          ' same number of CPUs and memory. You can use the Amazon EC2 Instance'
          ' Selector tool (https://github.com/aws/amazon-ec2-instance-selector)'
          ' to choose instance types with matching CPU and memory'
          ' configurations.'.format(kind)
      ),
  )


def AddOnDemandOrSpotInstanceType(parser, kind='node pool'):
  """Adds instance configurtion for creating node pool."""
  group = parser.add_group('Node pool instance configuration', mutex=True)
  AddInstanceType(group, kind)
  AddSpotInstanceTypes(group, kind)


def GetSpotInstanceTypes(args):
  return getattr(args, 'spot_instance_types', None)


def AddSshEC2KeyPair(parser, kind='control plane'):
  """Adds the --ssh-ec2-key-pair flag."""
  parser.add_argument(
      '--ssh-ec2-key-pair',
      help=(
          "Name of the EC2 key pair authorized to login to the {}'s nodes."
          .format(kind)
      ),
  )


def GetSshEC2KeyPair(args):
  return getattr(args, 'ssh_ec2_key_pair', None)


def AddClearSshEc2KeyPair(parser, kind):
  """Adds the --clear-ssh-ec2-key-pair flag."""
  parser.add_argument(
      '--clear-ssh-ec2-key-pair',
      action='store_true',
      default=None,
      help=(
          "Clear the EC2 key pair authorized to login to the {}'s nodes."
          .format(kind)
      ),
  )


def AddSshEC2KeyPairForUpdate(parser, kind='control plane'):
  """Adds SSH config EC2 key pair related flags for update."""
  group = parser.add_group('SSH config', mutex=True)
  AddSshEC2KeyPair(group, kind)
  AddClearSshEc2KeyPair(group, kind)


def AddRoleArn(parser, required=True):
  parser.add_argument(
      '--role-arn',
      required=required,
      help=(
          'Amazon Resource Name (ARN) of the IAM role to assume when '
          'managing AWS resources.'
      ),
  )


def GetRoleArn(args):
  return getattr(args, 'role_arn', None)


def AddRoleSessionName(parser):
  parser.add_argument(
      '--role-session-name', help='Identifier for the assumed role session.'
  )


def GetRoleSessionName(args):
  return getattr(args, 'role_session_name', None)


def AddSecurityGroupIds(parser, kind='control plane'):
  """Adds the --security-group-ids flag."""
  parser.add_argument(
      '--security-group-ids',
      type=arg_parsers.ArgList(),
      metavar='SECURITY_GROUP_ID',
      help=(
          "IDs of additional security groups to add to the {}'s nodes.".format(
              kind
          )
      ),
  )


def GetSecurityGroupIds(args):
  return getattr(args, 'security_group_ids', None) or []


def AddClearSecurityGroupIds(parser, noun):
  """Adds flag for clearing the security groups.

  Args:
    parser: The argparse.parser to add the arguments to.
    noun: The resource type to which the flag is applicable.
  """

  parser.add_argument(
      '--clear-security-group-ids',
      action='store_true',
      default=None,
      help=(
          'Clear any additional security groups associated with the '
          "{}'s nodes. This does not remove the default security groups."
          .format(noun)
      ),
  )


def AddSecurityGroupFlagsForUpdate(parser, noun):
  """Adds security group related flags for update.

  Args:
    parser: The argparse.parser to add the arguments to.
    noun: The resource type to which the flags are applicable.
  """

  group = parser.add_group('Security groups', mutex=True)
  AddSecurityGroupIds(group, noun)
  AddClearSecurityGroupIds(group, noun)


def AddPerNodePoolSGRules(parser):
  """Adds --disable-per-node-pool-sg-rules flag to parser."""

  parser.add_argument(
      '--disable-per-node-pool-sg-rules',
      action='store_true',
      default=None,
      dest='per_node_pool_sg_rules_disabled',
      help=(
          'Disable the default per node pool subnet security group rules on '
          'the control plane security group. When disabled, at least one '
          'security group that allows node pools to send traffic to '
          'the control plane on ports TCP/443 and TCP/8132 must be provided.'
      ),
  )


def GetPerNodePoolSGRulesDisabled(parser):
  return getattr(parser, 'per_node_pool_sg_rules_disabled', None)


def AddPerNodePoolSGRulesForUpdate(parser):
  """Adds --disable-per-node-pool-sg-rules and --enable-per-node-pool-sg-rules flags to parser."""

  group = parser.add_group(
      'Default per node pool security group rules', mutex=True
  )
  AddPerNodePoolSGRules(group)
  group.add_argument(
      '--enable-per-node-pool-sg-rules',
      action='store_false',
      default=None,
      dest='per_node_pool_sg_rules_disabled',
      help=(
          'Enable the default per node pool subnet security group rules on '
          'the control plane security group.'
      ),
  )


def _VolumeTypeEnumMapper(prefix):
  return arg_utils.ChoiceEnumMapper(
      '--{}-volume-type'.format(prefix),
      api_util.GetMessagesModule().GoogleCloudGkemulticloudV1AwsVolumeTemplate.VolumeTypeValueValuesEnum,
      include_filter=lambda volume_type: 'UNSPECIFIED' not in volume_type,
      help_str='Type of the {} volume.'.format(prefix),
  )


def AddRootVolumeType(parser):
  _VolumeTypeEnumMapper('root').choice_arg.AddToParser(parser)


def AddMainVolumeType(parser):
  _VolumeTypeEnumMapper('main').choice_arg.AddToParser(parser)


def GetRootVolumeType(args):
  if getattr(args, 'root_volume_type', None):
    return _VolumeTypeEnumMapper('root').GetEnumForChoice(args.root_volume_type)


def GetMainVolumeType(args):
  if getattr(args, 'main_volume_type', None):
    return _VolumeTypeEnumMapper('main').GetEnumForChoice(args.main_volume_type)


def _AddVolumeIops(parser, prefix):
  parser.add_argument(
      '--{}-volume-iops'.format(prefix),
      type=int,
      help=(
          'Number of I/O operations per second (IOPS) to provision '
          'for the {} volume.'.format(prefix)
      ),
  )


def AddRootVolumeIops(parser):
  _AddVolumeIops(parser, 'root')


def GetRootVolumeIops(args):
  return getattr(args, 'root_volume_iops', None)


def AddMainVolumeIops(parser):
  _AddVolumeIops(parser, 'main')


def GetMainVolumeIops(args):
  return getattr(args, 'main_volume_iops', None)


def _AddVolumeThroughput(parser, prefix):
  parser.add_argument(
      '--{}-volume-throughput'.format(prefix),
      type=int,
      help=(
          'Throughput to provision for the {} volume, in MiB/s. Only valid '
          'if the volume type is GP3. If volume type is GP3 and throughput '
          'is not provided, it defaults to 125.'.format(prefix)
      ),
  )


def AddRootVolumeThroughput(parser):
  _AddVolumeThroughput(parser, 'root')


def GetRootVolumeThroughput(args):
  return getattr(args, 'root_volume_throughput', None)


def AddMainVolumeThroughput(parser):
  _AddVolumeThroughput(parser, 'main')


def GetMainVolumeThroughput(args):
  return getattr(args, 'main_volume_throughput', None)


def _AddKmsKeyArn(parser, prefix, target, required=False):
  parser.add_argument(
      '--{}-kms-key-arn'.format(prefix),
      required=required,
      help=(
          'Amazon Resource Name (ARN) of the AWS KMS key to encrypt the {}.'
          .format(target)
      ),
  )


def AddRootVolumeKmsKeyArn(parser):
  _AddKmsKeyArn(parser, 'root-volume', 'root volume')


def GetRootVolumeKmsKeyArn(args):
  return getattr(args, 'root_volume_kms_key_arn', None)


def AddMainVolumeKmsKeyArn(parser):
  _AddKmsKeyArn(parser, 'main-volume', 'main volume')


def GetMainVolumeKmsKeyArn(args):
  return getattr(args, 'main_volume_kms_key_arn', None)


def AddDatabaseEncryptionKmsKeyArn(parser):
  _AddKmsKeyArn(parser, 'database-encryption', 'cluster secrets', required=True)


def GetDatabaseEncryptionKmsKeyArn(args):
  return getattr(args, 'database_encryption_kms_key_arn', None)


def AddConfigEncryptionKmsKeyArn(parser, required=True):
  _AddKmsKeyArn(parser, 'config-encryption', 'user data', required=required)


def GetConfigEncryptionKmsKeyArn(args):
  return getattr(args, 'config_encryption_kms_key_arn', None)


def _TenancyEnumMapper():
  return arg_utils.ChoiceEnumMapper(
      '--instance-placement',
      api_util.GetMessagesModule().GoogleCloudGkemulticloudV1AwsInstancePlacement.TenancyValueValuesEnum,
      include_filter=lambda tenancy: 'UNSPECIFIED' not in tenancy,
      help_str='Type of the tenancy.',
  )


def AddInstancePlacement(parser):
  return _TenancyEnumMapper().choice_arg.AddToParser(parser)


def GetInstancePlacement(args):
  instance_placement = getattr(args, 'instance_placement', None)
  return (
      _TenancyEnumMapper().GetEnumForChoice(instance_placement)
      if instance_placement
      else None
  )


def AddClearProxyConfig(parser, noun):
  """Adds flag for clearing the proxy configuration.

  Args:
    parser: The argparse.parser to add the arguments to.
    noun: The resource type to which the flag is applicable.
  """

  parser.add_argument(
      '--clear-proxy-config',
      action='store_true',
      default=None,
      help='Clear the proxy configuration associated with the {}.'.format(noun),
  )


def AddProxySecretArn(parser, required=False):
  parser.add_argument(
      '--proxy-secret-arn',
      required=required,
      help=(
          'ARN of the AWS Secrets Manager secret that contains a proxy '
          'configuration.'
      ),
  )


def GetProxySecretArn(args):
  return getattr(args, 'proxy_secret_arn', None)


def AddProxySecretVersionId(parser, required=False):
  parser.add_argument(
      '--proxy-secret-version-id',
      required=required,
      help=(
          'Version ID string of the AWS Secrets Manager secret that contains '
          'a proxy configuration.'
      ),
  )


def GetProxySecretVersionId(args):
  return getattr(args, 'proxy_secret_version_id', None)


def AddProxyConfig(parser):
  """Adds proxy configuration flags.

  Args:
    parser: The argparse.parser to add the arguments to.
  """

  group = parser.add_argument_group('Proxy config')
  AddProxySecretArn(group, required=True)
  AddProxySecretVersionId(group, required=True)


def AddProxyConfigForUpdate(parser, noun):
  """Adds proxy configuration flags for update.

  Args:
    parser: The argparse.parser to add the arguments to.
    noun: The resource type to which the flags are applicable.
  """

  group = parser.add_group('Proxy config', mutex=True)
  update_proxy_group = group.add_group(
      'Update existing proxy config parameters'
  )
  AddProxySecretArn(update_proxy_group)
  AddProxySecretVersionId(update_proxy_group)
  AddClearProxyConfig(group, noun)


def GetSubnetIds(args):
  return getattr(args, 'subnet_ids', None) or []


def AddAutoScalingMetricsCollection(parser):
  """Adds autoscaling metrics collection flags.

  Args:
    parser: The argparse.parser to add the arguments to.
  """

  group = parser.add_argument_group('Node pool autoscaling metrics collection')
  AddAutoscalingMetricsGranularity(group, required=True)
  AddAutoscalingMetrics(group)


def AddAutoscalingMetricsGranularity(parser, required=False):
  parser.add_argument(
      '--autoscaling-metrics-granularity',
      required=required,
      help=(
          'Frequency at which EC2 Auto Scaling sends aggregated data to '
          'AWS CloudWatch. The only valid value is "1Minute".'
      ),
  )


def GetAutoscalingMetricsGranularity(args):
  return getattr(args, 'autoscaling_metrics_granularity', None)


def AddAutoscalingMetrics(parser):
  parser.add_argument(
      '--autoscaling-metrics',
      type=arg_parsers.ArgList(),
      metavar='AUTOSCALING_METRIC',
      required=False,
      help=(
          'Autoscaling metrics to enable. For a list of valid metrics, '
          'refer to https://docs.aws.amazon.com/autoscaling/ec2/APIReference/'
          'API_EnableMetricsCollection.html. If granularity is specified '
          'but not any metrics, all metrics are enabled.'
      ),
  )


def GetAutoscalingMetrics(args):
  return getattr(args, 'autoscaling_metrics', None)


def AddAutoScalingMetricsCollectionForUpdate(parser):
  """Adds autoscaling metrics collection flags for update.

  Args:
    parser: The argparse.parser to add the arguments to.
  """

  group = parser.add_group(
      'Node pool autoscaling metrics collection', mutex=True
  )
  update_metrics_group = group.add_group(
      'Update existing cloudwatch autoscaling metrics collection parameters'
  )
  AddAutoscalingMetricsGranularity(update_metrics_group)
  AddAutoscalingMetrics(update_metrics_group)
  AddClearAutoscalingMetrics(group)


def AddClearAutoscalingMetrics(parser):
  """Adds flag for clearing the cloudwatch autoscaling metrics collection.

  Args:
    parser: The argparse.parser to add the arguments to.
  """

  parser.add_argument(
      '--clear-autoscaling-metrics',
      action='store_true',
      default=None,
      help=(
          'Clear the cloudwatch autoscaling metrics collection '
          'associated with the nodepool.'
      ),
  )


def AddKubeletConfigCpuManagerPolicy(parser):
  """Sets kubelet configuration CPU manager policy.

  Args:
    parser: The argparse.parser to add the arguments to.
  """
  parser.add_argument(
      '--kubelet-config-cpu-manager-policy',
      required=False,
      help=(
          'Kubelet CPU manager policy.'
      ),
      choices=['none', 'static']
  )


def GetKubeletConfigCpuManagerPolicy(args):
  return getattr(args, 'kubelet_config_cpu_manager_policy', None)


def AddKubeletConfigCpuCfsQuota(parser):
  """Sets kubelet configuration CPU CFS quota.

  Args:
    parser: The argparse.parser to add the arguments to.
  """
  parser.add_argument(
      '--kubelet-config-cpu-cfs-quota',
      type=bool,
      required=False,
      help=(
          'Enforce a Kubelet CPU CFS quota.'
      ),
  )


def GetKubeletConfigCpuCfsQuota(args):
  return getattr(args, 'kubelet_config_cpu_cfs_quota', None)


def AddKubeletConfigCpuCfsQuotaPeriod(parser):
  """Sets kubelet configuration CPU CFS quota period.

  Args:
    parser: The argparse.parser to add the arguments to.
  """
  parser.add_argument(
      '--kubelet-config-cpu-cfs-quota-period',
      required=False,
      help=(
          'Kubelet CPU CFS quota period, within the range "1ms" to "1s".'
      ),
  )


def GetKubeletConfigCpuCfsQuotaPeriod(args):
  return getattr(args, 'kubelet_config_cpu_cfs_quota_period', None)


def AddKubeletConfigPodPidsLimit(parser):
  """Sets kubelet configuration pod PIDS limit.

  Args:
    parser: The argparse.parser to add the arguments to.
  """
  parser.add_argument(
      '--kubelet-config-pod-pids-limit',
      type=int,
      required=False,
      help=(
          'Kubelet maximum number of PIDS in any pod, within the '
          'range 1024 to 4194304.'
      ),
  )


def GetKubeletConfigPodPidsLimit(args):
  return getattr(args, 'kubelet_config_pod_pids_limit', None)
