# -*- coding: utf-8 -*- #
# Copyright 2022 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.
"""Command to create an Immersive Stream for XR service instance."""


from googlecloudsdk.api_lib.immersive_stream.xr import api_util
from googlecloudsdk.api_lib.immersive_stream.xr import instances
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.immersive_stream.xr import flags
from googlecloudsdk.command_lib.immersive_stream.xr import resource_args
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core import resources


@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Create(base.CreateCommand):
  """Create an Immersive Stream for XR service instance."""

  detailed_help = {
      'DESCRIPTION': 'Create an Immersive Stream for XR service instance.',
      'EXAMPLES': """
          To create a service instance called `my-instance` serving content
          `my-content` with version `my-version` that has availablilty for 2
          concurent sessions in us-west1 region and 3 concurrent sessions in
          us-east4 region, run:

            $ {command} my-instance --content=my-content --version=my-version --add-region=region=us-west1,capacity=2 --add-region=region=us-east4,capacity=3

          Optionally, a fallback url may be specified. Users will be redirected
          to this fallback url when the service instance is unable to provide
          the streaming experience.
          To create a service instance called `my-instance` serving content
          `my-content` with version `my-version` that has availablilty for 2
          concurent sessions in us-west1 and uses fallback url
          `https://www.google.com` run:

            $ {command} my-instance --content=my-content --version=my-version --add-region=region=us-west1,capacity=2 --fallback-url="https://www.google.com"

           By default, the instance is created with mode=ar, which supports both
           3D and AR experiences. Instances can also be configured to use
           3D-only mode. This configuration cannot be updated later.
           To use 3D-only mode, include:

            --mode=3d

           By default, the instance is created with gpu-class=t4. This uses the
           NVIDIA T4 GPU for the instance. Instances can also be configured to
           use NVIDIA L4 GPUs at creation. Note that only certain regions are
           available for L4, and only 3D-only mode is supported. This
           configuration cannot be updated later.
           To use NVIDIA L4 GPU for the instance, include:

            --gpu-class=l4
      """,
  }

  @staticmethod
  def __ValidateArgs(args):
    return flags.ValidateRegionConfigArgs(args.add_region, 'add')

  @staticmethod
  def Args(parser):
    resource_args.AddContentResourceArg(
        parser, verb='served by the instance', positional=False
    )
    parser.add_argument('instance', help='Name of the instance to be created')
    parser.add_argument(
        '--version',
        required=True,
        help='Build version tag of the content served by this instance',
    )
    parser.add_argument(
        '--fallback-url',
        help=(
            'Fallback url to redirect users to when this service instance is'
            ' unable to provide the streaming experience'
        ),
        required=False,
    )
    parser.add_argument(
        '--mode',
        help='The rendering mode that is supported by this service instance',
        required=False,
    )
    parser.add_argument(
        '--gpu-class',
        help='The class of GPU that is used by this service instance',
        required=False,
    )
    flags.AddRegionConfigArg('--add-region', parser)
    base.ASYNC_FLAG.AddToParser(parser)

  def Run(self, args):
    if not Create.__ValidateArgs(args):
      return

    region_configs = args.add_region
    content_ref = args.CONCEPTS.content.Parse()
    content_name = content_ref.RelativeName()
    location = content_ref.locationsId
    instance_name = args.instance
    version = args.version
    fallback_url = args.fallback_url
    mode = args.mode
    gpu_class = args.gpu_class

    if fallback_url and not flags.ValidateUrl(fallback_url):
      return

    if mode and not flags.ValidateMode(mode):
      return

    if gpu_class and not flags.ValidateGpuClass(gpu_class, mode):
      return

    client = api_util.GetClient(self.ReleaseTrack())
    target_location_configs = instances.GenerateTargetLocationConfigs(
        self.ReleaseTrack(),
        add_region_configs=region_configs,
        update_region_configs=None,
        remove_regions=None,
        current_instance=None,
    )
    result_operation = instances.Create(
        self.ReleaseTrack(),
        instance_name,
        content_name,
        location,
        version,
        target_location_configs,
        fallback_url,
        mode,
        gpu_class,
    )
    log.status.Print('Create request issued for: [{}]'.format(instance_name))
    if args.async_:
      log.status.Print(
          'Check operation [{}] for status.\n'.format(result_operation.name)
      )
      return result_operation

    operation_resource = resources.REGISTRY.Parse(
        result_operation.name,
        api_version=api_util.GetApiVersion(self.ReleaseTrack()),
        collection='stream.projects.locations.operations',
    )
    created_instance = waiter.WaitFor(
        waiter.CloudOperationPoller(
            client.projects_locations_streamInstances,
            client.projects_locations_operations,
        ),
        operation_resource,
        'Waiting for operation [{}] to complete'.format(result_operation.name),
    )

    instance_resource = resources.REGISTRY.Parse(
        None,
        collection='stream.projects.locations.streamInstances',
        api_version=api_util.GetApiVersion(self.ReleaseTrack()),
        params={
            'projectsId': properties.VALUES.core.project.Get(required=True),
            'locationsId': 'global',
            'streamInstancesId': instance_name,
        },
    )

    log.CreatedResource(instance_resource)

    return created_instance
