# -*- coding: utf-8 -*- #
# Copyright 2023 Google Inc. 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.
"""`gcloud dataproc-gdc instances create` command."""

from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

from apitools.base.py import encoding
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope.concepts import concepts
from googlecloudsdk.command_lib.edge_cloud.container import resource_args as gdce_resource_args
from googlecloudsdk.command_lib.iam import iam_util
from googlecloudsdk.command_lib.util.apis import yaml_data
from googlecloudsdk.command_lib.util.args import labels_util
from googlecloudsdk.command_lib.util.concepts import concept_parsers
from googlecloudsdk.command_lib.util.concepts import presentation_specs
from googlecloudsdk.core import log
from googlecloudsdk.core import resources


DATAPROCGDC_API_NAME = 'dataprocgdc'
DATAPROCGDC_API_VERSION = 'v1alpha1'


@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
@base.DefaultUniverseOnly
class Create(base.CreateCommand):
  """Create a Dataproc GDC service instance.

  A service instance is a deployment of the Dataproc operator running on a
  Kubernetes cluster. Each cluster may have at most one Dataproc service
  instance deployed. A service instance manages Application Environments
  and Spark Applications that run locally on the cluster.
  """

  detailed_help = {'EXAMPLES': """\
          To create a Dataproc GDC service instance with name `my-instance`
          in location `us-central1` running on a GDCE cluster named
          `my-cluster`, run:

          $ {command} my-instance --location=us-central1 --gdce-cluster=my-cluster

          Note that the GDCE cluster and the Dataproc GDC service instance must
          be in the same project and Cloud location (in this case us-central1).
          """}

  @staticmethod
  def Args(parser):
    concept_parsers.ConceptParser(
        [
            GetInstanceResourcePresentationSpec(),
            GetGdceClusterResourcePresentationSpec(),
        ],
        command_level_fallthroughs={
            # Set the GDCE cluster location to the instance location
            '--gdce-cluster.location': ['instance.location']
        },
    ).AddToParser(parser)
    parser.add_argument(
        '--request-id',
        help="""An optional request ID to identify requests. If the service receives two identical
        instance create requests with the same request_id, the second request is
        ignored and the operation that corresponds to the first request is returned for both.

        The request ID must be a valid UUID with the exception that zero UUID is
        not supported (00000000-0000-0000-0000-000000000000).""",
    )
    parser.add_argument(
        '--display-name',
        help=(
            'Human-readable name for this service instance to be used in user'
            ' interfaces.'
        ),
    )
    parser.add_argument(
        '--annotations',
        metavar='KEY=VALUE',
        type=arg_parsers.ArgDict(),
        action=arg_parsers.UpdateAction,
        help=(
            'List of annotation KEY=VALUE pairs to add to the service instance.'
        ),
    )
    parser.add_argument(
        '--service-account',
        type=iam_util.GetIamAccountFormatValidator(),
        help=""" Requested google cloud service account to associate with the ServiceInstance.

        Service account must be of format my-iam-account@somedomain.com or
        my-iam-account@my-project.iam.gserviceaccount.com""",
    )
    labels_util.AddCreateLabelsFlags(parser)
    base.ASYNC_FLAG.AddToParser(parser)

  def Run(self, args):
    dataprocgdc_client = apis.GetClientInstance(
        DATAPROCGDC_API_NAME, DATAPROCGDC_API_VERSION
    )
    messages = apis.GetMessagesModule('dataprocgdc', 'v1alpha1')
    instance_ref = args.CONCEPTS.instance.Parse()
    cluster_ref = args.CONCEPTS.gdce_cluster.Parse()

    if args.annotations:
      annotations = encoding.DictToAdditionalPropertyMessage(
          args.annotations,
          messages.ServiceInstance.AnnotationsValue,
          sort_items=True,
      )
    else:
      annotations = None

    create_req = (
        messages.DataprocgdcProjectsLocationsServiceInstancesCreateRequest(
            serviceInstanceId=instance_ref.Name(),
            parent=instance_ref.Parent().RelativeName(),
            requestId=args.request_id,
            serviceInstance=messages.ServiceInstance(
                displayName=args.display_name,
                labels=labels_util.ParseCreateArgs(
                    args, messages.ServiceInstance.LabelsValue
                ),
                annotations=annotations,
                gdceCluster=messages.GdceCluster(
                    gdceCluster=cluster_ref.RelativeName()
                ),
                serviceAccount=args.service_account,
            ),
        )
    )

    create_op = dataprocgdc_client.projects_locations_serviceInstances.Create(
        create_req
    )

    async_ = getattr(args, 'async_', False)
    if not async_:
      # Poll for operation
      operation_ref = resources.REGISTRY.Parse(
          create_op.name, collection='dataprocgdc.projects.locations.operations'
      )
      poller = waiter.CloudOperationPoller(
          dataprocgdc_client.projects_locations_serviceInstances,
          dataprocgdc_client.projects_locations_operations,
      )
      waiter.WaitFor(
          poller,
          operation_ref,
          'Waiting for service instance create operation [{0}]'.format(
              operation_ref.RelativeName()
          ),
      )
      log.CreatedResource(
          instance_ref.Name(),
          details=(
              '- service instance created in [{0}] for cluster [{1}]'.format(
                  instance_ref.Parent().RelativeName(),
                  cluster_ref.RelativeName(),
              )
          ),
      )
      return

    log.status.Print(
        'Create request issued for: [{0}]\nCheck operation [{1}] for status.'
        .format(instance_ref.Name(), create_op.name)
    )


def GetInstanceResourcePresentationSpec():
  instance_data = yaml_data.ResourceYAMLData.FromPath(
      'dataproc_gdc.instance'
  )
  resource_spec = concepts.ResourceSpec.FromYaml(instance_data.GetData())
  return presentation_specs.ResourcePresentationSpec(
      name='instance',
      concept_spec=resource_spec,
      group_help='Name of the service instance to create.',
      required=True,
      prefixes=False,
  )


def GetGdceClusterResourcePresentationSpec():
  return presentation_specs.ResourcePresentationSpec(
      name='--gdce-cluster',
      concept_spec=gdce_resource_args.GetClusterResourceSpec(),
      group_help='The GDCE cluster on which to create the service instance.',
      required=True,
      prefixes=True,
      # This hides the location flag for the GDCE cluster resource, since we
      # always enforce that the cluster is the same region as the instance
      flag_name_overrides={'location': ''},
  )
