# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Database Migration Service conversion workspaces CRUD API."""

from typing import Any, Mapping, Optional

from googlecloudsdk.api_lib.database_migration import api_util
from googlecloudsdk.api_lib.database_migration.conversion_workspaces import base_conversion_workspaces_client
from googlecloudsdk.api_lib.database_migration.conversion_workspaces import conversion_workspace_builder
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.database_migration.conversion_workspaces import enums
from googlecloudsdk.generated_clients.apis.datamigration.v1 import datamigration_v1_messages as messages


class ConversionWorkspacesCRUDClient(
    base_conversion_workspaces_client.BaseConversionWorkspacesClient
):
  """Client for Conversion Workspaces CRUD API."""

  @property
  def cw_builder(
      self,
  ) -> conversion_workspace_builder.ConversionWorkspaceBuilder:
    """Returns an instance of the conversion workspace builder."""
    return conversion_workspace_builder.ConversionWorkspaceBuilder(
        release_track=self.release_track,
    )

  def Create(
      self,
      parent_ref: str,
      conversion_workspace_id: str,
      display_name: str,
      source_database_provider: enums.SourceDatabaseProvider,
      source_database_engine: enums.SourceDatabaseEngine,
      source_database_version: str,
      destination_database_provider: enums.DestinationDatabaseProvider,
      destination_database_engine: enums.DestinationDatabaseEngine,
      destination_database_version: str,
      global_settings: messages.ConversionWorkspace.GlobalSettingsValue,
  ) -> messages.Operation:
    """Creates a conversion workspace.

    Args:
      parent_ref: a Resource reference to a parent
        datamigration.projects.locations resource for this conversion workspace.
      conversion_workspace_id: the name of the resource to create.
      display_name: the display name for the conversion workspace.
      source_database_provider: the source database provider for the conversion
        workspace.
      source_database_engine: the source database engine for the conversion
        workspace.
      source_database_version: the source database version for the conversion
        workspace.
      destination_database_provider: the destination database provider for the
        conversion workspace.
      destination_database_engine: the destination database engine for the
        conversion workspace.
      destination_database_version: the destination database version for the
        conversion workspace.
      global_settings: GlobalSettings, the global settings for the conversion
        workspace.

    Returns:
      Operation: the operation for creating the conversion workspace.
    """
    if global_settings and global_settings.additionalProperties:
      props = {
          prop.key: prop.value for prop in global_settings.additionalProperties
      }
      if (
          props.get('autoAssessment') == 'true'
          and props.get('aiConversion') == 'false'
      ):
        raise exceptions.InvalidArgumentException(
            '--quality-assessment',
            'cannot be true if --auto-conversion is false.',
        )
    return self.cw_service.Create(
        self.messages.DatamigrationProjectsLocationsConversionWorkspacesCreateRequest(
            conversionWorkspace=self.cw_builder.Build(
                display_name=display_name,
                source_database_provider=source_database_provider,
                source_database_engine=source_database_engine,
                source_database_version=source_database_version,
                destination_database_provider=destination_database_provider,
                destination_database_engine=destination_database_engine,
                destination_database_version=destination_database_version,
                global_settings=global_settings,
            ),
            conversionWorkspaceId=conversion_workspace_id,
            parent=parent_ref,
            requestId=api_util.GenerateRequestId(),
        ),
    )

  def Read(self, name: str):
    return self.cw_service.Get(
        self.messages.DatamigrationProjectsLocationsConversionWorkspacesGetRequest(
            name=name,
        )
    )

  def GetGlobalFilter(self, name: str) -> str:
    """Get global filter for a conversion workspace.

    If no global filter is set, '*' will be returned.

    Args:
      name: The name of the conversion workspace.

    Returns:
      The global filter for the conversion workspace.
    """
    return self._GetAdditionalProperties(name).get('filter', '*')

  def _GetAdditionalProperties(self, name: str) -> Mapping[str, Any]:
    """Get conversion workspace additional properties.

    Args:
      name: The name of the conversion workspace.

    Returns:
      The conversion workspace additional properties.
    """
    conversion_workspace = self.Read(name=name)
    if not conversion_workspace.globalSettings:
      return {}

    return {
        additional_property.key: additional_property.value
        for additional_property in (
            conversion_workspace.globalSettings.additionalProperties
        )
    }

  def Update(
      self,
      name: str,
      display_name: Optional[str],
      global_filter: Optional[str],
      auto_conversion: Optional[bool] = None,
      quality_assessment: Optional[bool] = None,
      conversion_assistance: Optional[bool] = None,
      pattern_matching: Optional[bool] = None,
  ):
    """Updates a conversion workspace.

    Args:
      name: str, the reference of the conversion workspace to update.
      display_name: the display name to update.
      global_filter: the global filter for the conversion workspace.
      auto_conversion: whether to enable auto-conversion.
      quality_assessment: whether to enable quality assessment.
      conversion_assistance: whether to enable conversion assistance.
      pattern_matching: whether to enable pattern matching.

    Returns:
      Operation: the operation for updating the conversion workspace.
    """
    conversion_workspace, update_fields = self._GetUpdatedConversionWorkspace(
        conversion_workspace=self.Read(name),
        display_name=display_name,
        global_filter=global_filter,
        auto_conversion=auto_conversion,
        quality_assessment=quality_assessment,
        conversion_assistance=conversion_assistance,
        pattern_matching=pattern_matching,
    )
    return self.cw_service.Patch(
        self.messages.DatamigrationProjectsLocationsConversionWorkspacesPatchRequest(
            conversionWorkspace=conversion_workspace,
            name=name,
            requestId=api_util.GenerateRequestId(),
            updateMask=','.join(update_fields),
        ),
    )

  def Delete(self, name: str):
    """Deletes a conversion workspace.

    Args:
      name: str, the name of the resource to delete.

    Returns:
      Operation: the operation for deleting the conversion workspace.
    """
    return self.cw_service.Delete(
        self.messages.DatamigrationProjectsLocationsConversionWorkspacesDeleteRequest(
            name=name,
            requestId=api_util.GenerateRequestId(),
        ),
    )

  def _GetUpdatedConversionWorkspace(
      self,
      conversion_workspace: messages.ConversionWorkspace,
      display_name: Optional[str],
      global_filter: Optional[str],
      auto_conversion: Optional[bool] = None,
      quality_assessment: Optional[bool] = None,
      conversion_assistance: Optional[bool] = None,
      pattern_matching: Optional[bool] = None,
  ) -> tuple[messages.ConversionWorkspace, set[str]]:
    """Returns updated conversion workspace and list of updated fields.

    Args:
      conversion_workspace: the conversion workspace to update.
      display_name: the display name to update.
      global_filter: the global filter for the conversion workspace.
      auto_conversion: whether to enable auto-conversion.
      quality_assessment: whether to enable quality assessment.
      conversion_assistance: whether to enable conversion assistance.
      pattern_matching: whether to enable pattern matching.

    Returns:
      A tuple containing:
        The updated conversion workspace object.
        A set of the names of the updated fields.
    """
    update_fields = set()

    if display_name:
      conversion_workspace.displayName = display_name
      update_fields.add('displayName')

    current_settings = {}
    if conversion_workspace.globalSettings:
      for prop in (
          conversion_workspace.globalSettings.additionalProperties or []
      ):
        current_settings[prop.key] = prop.value

    new_settings = current_settings.copy()

    if auto_conversion is not None:
      new_settings['aiConversion'] = str(auto_conversion).lower()
      if not auto_conversion:
        new_settings['autoAssessment'] = str(auto_conversion).lower()
    if quality_assessment is not None:
      new_settings['autoAssessment'] = str(quality_assessment).lower()
    if global_filter is not None:
      new_settings['filter'] = global_filter
    if conversion_assistance is not None:
      new_settings['aiAssistant'] = str(conversion_assistance).lower()
    if pattern_matching is not None:
      new_settings['aiPatternApplier'] = str(pattern_matching).lower()

    if (
        new_settings.get('autoAssessment') == 'true'
        and new_settings.get('aiConversion', 'false') == 'false'
    ):
      raise exceptions.InvalidArgumentException(
          '--quality-assessment',
          'cannot be true if auto-conversion is false.',
      )

    if new_settings != current_settings:
      update_fields.add('globalSettings')
      properties = []
      for key, value in sorted(new_settings.items()):
        properties.append(
            self.messages.ConversionWorkspace.GlobalSettingsValue.AdditionalProperty(
                key=key, value=value
            )
        )
      conversion_workspace.globalSettings = (
          self.messages.ConversionWorkspace.GlobalSettingsValue(
              additionalProperties=properties
          )
      )

    return conversion_workspace, update_fields
