# -*- coding: utf-8 -*- #
# Copyright 2018 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.
"""The gcloud datastore indexes cleanup command."""


from googlecloudsdk.api_lib.app import yaml_parsing
from googlecloudsdk.api_lib.datastore import constants
from googlecloudsdk.api_lib.datastore import index_api
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.calliope import parser_arguments
from googlecloudsdk.command_lib.app import output_helpers
from googlecloudsdk.command_lib.datastore import flags
from googlecloudsdk.core import properties
from googlecloudsdk.core.console import console_io


@base.DefaultUniverseOnly
@base.ReleaseTracks(
    base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Cleanup(base.Command):
  """Cleanup Cloud Datastore indexes."""

  detailed_help = {
      'brief': (
          'Remove unused datastore indexes based on your local index '
          'configuration.'
      ),
      'DESCRIPTION': """
This command removes unused datastore indexes based on your local index
configuration. Any indexes that exist that are not in the index file will be
removed.
      """,
      'EXAMPLES': """\
          To remove unused indexes based on your local configuration, run:

            $ {command} ~/myapp/index.yaml
          """,
  }

  @staticmethod
  def Args(parser: parser_arguments.ArgumentInterceptor) -> None:
    """Get arguments for this command.

    Args:
      parser: argparse.ArgumentParser, the parser for this command.
    """
    flags.AddIndexFileFlag(parser)
    flags.AddDatabaseIdFlag(parser)

  def Run(self, args) -> None:
    """Deletes indexes that have been removed from the index.yaml file."""
    # Default to '(default)' if unset.
    database_id = (
        args.database if args.database else constants.DEFAULT_NAMESPACE
    )
    self.Cleanup(index_file=args.index_file, database=database_id)

  def Cleanup(self, index_file: str, database: str) -> None:
    """Delete indexes that have been removed from the index.yaml file."""
    project = properties.VALUES.core.project.Get(required=True)
    info = yaml_parsing.ConfigYamlInfo.FromFile(index_file)
    if not info or info.name != yaml_parsing.ConfigYamlInfo.INDEX:
      raise exceptions.InvalidArgumentException(
          'index_file', 'You must provide the path to a valid index.yaml file.'
      )
    output_helpers.DisplayProposedConfigDeployments(
        project=project, configs=[info]
    )
    console_io.PromptContinue(
        default=True, throw_if_unattended=False, cancel_on_no=True
    )
    self.PerformApiCleanupViaFirestoreAdmin(info, project, database)

  def PerformApiCleanupViaFirestoreAdmin(
      self, info: yaml_parsing.ConfigYamlInfo, project: str, database: str
  ) -> None:
    """Cleans up removed indexes via the Firestore Admin API.

    Lists the database's existing indexes, and then compares them against the
    indexes that are defined in the given index.yaml file. Any discrepancies
    against the index.yaml file are deleted.

    Args:
      info: The parsed index.yaml information.
      project: The project we are operating on.
      database: The database within the project we are operating on.
    """
    received_indexes = (
        index_api.NormalizeIndexesForFirestoreApi(info.parsed.indexes or [])
    )
    indexes_to_delete_ids = set()
    current_indexes = index_api.ListDatastoreIndexesViaFirestoreApi(
        project, database
    )
    for index_id, index in current_indexes:
      # Firestore API returns index with '__name__' field path. Normalizing the
      # index is required.
      normalized_index = index_api.NormalizeIndexForFirestoreApi(index)
      if normalized_index in received_indexes:
        continue
      msg = (
          'This index is no longer defined in your index.yaml file.\n{0}'
          .format(index.ToYAML())
      )
      prompt = 'Do you want to delete this index'
      if console_io.PromptContinue(msg, prompt, default=True):
        indexes_to_delete_ids.add(index_id)
    index_api.DeleteIndexesViaFirestoreApi(
        project, database, indexes_to_delete_ids
    )
