# -*- 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.
"""Base class for gkemulticloud API clients for operations."""

from apitools.base.py import encoding
from googlecloudsdk.api_lib.container.gkemulticloud import client
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.command_lib.container.gkemulticloud import constants
from googlecloudsdk.core import log
from googlecloudsdk.core.console import progress_tracker


class OperationsClient(client.ClientBase):
  """Client for managing LROs."""

  def __init__(self, **kwargs):
    super(OperationsClient, self).__init__(**kwargs)
    self._service = self._client.projects_locations_operations
    self._list_result_field = 'operations'

  def Wait(self, operation_ref, message):
    """Waits for an LRO to complete.

    Args:
      operation_ref: object, passed to operation poller poll method.
      message: str, string to display for the progress tracker.
    """
    poller = _Poller(self._service)
    waiter.WaitFor(
        poller=poller,
        operation_ref=operation_ref,
        custom_tracker=progress_tracker.ProgressTracker(
            message=message,
            detail_message_callback=poller.GetDetailMessage,
            aborted_message='Aborting wait for operation {}.\n'.format(
                operation_ref
            ),
        ),
        wait_ceiling_ms=constants.MAX_LRO_POLL_INTERVAL_MS,
        max_wait_ms=constants.MAX_LRO_WAIT_MS,
    )

  def Cancel(self, operation_ref):
    """Cancels an ongoing LRO.

    Args:
      operation_ref: object, operation resource to be canceled.
    """
    request_type = self._service.GetRequestType('Cancel')
    self._service.Cancel(request_type(name=operation_ref.RelativeName()))


class _Poller(waiter.CloudOperationPollerNoResources):
  """Poller for Anthos Multi-cloud operations.

  The poller stores the status detail from the operation message to update
  the progress tracker.
  """

  def __init__(self, operation_service):
    """See base class."""
    self.operation_service = operation_service
    self.status_detail = None
    self.last_error_detail = None

  def Poll(self, operation_ref):
    """See base class."""
    request_type = self.operation_service.GetRequestType('Get')
    operation = self.operation_service.Get(
        request_type(name=operation_ref.RelativeName())
    )
    if operation.metadata is not None:
      metadata = encoding.MessageToPyValue(operation.metadata)
      if 'statusDetail' in metadata:
        self.status_detail = metadata['statusDetail']
      if 'errorDetail' in metadata:
        error_detail = metadata['errorDetail']
        if error_detail != self.last_error_detail:
          log.error(error_detail)
        self.last_error_detail = error_detail
    return operation

  def GetDetailMessage(self):
    return self.status_detail
