content: /*
   * Copyright 1999-2022 Alibaba Group Holding Ltd.
   *
   * 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.
   */
  
  package com.alibaba.nacos.api.ability.constant;
  
  import java.util.Collection;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.stream.Collectors;
  
  /**
   * Ability key constant. It is used to constrain the ability key.<br/>
   * <strong>Ensure that return value of {@link AbilityKey#getName()} is unique under one specify {@link AbilityMode}</strong>.
   *
   * @author Daydreamer
   * @date 2022/8/31 12:27
   **/
  public enum AbilityKey {
      
      /**
       * Server support register or deregister persistent instance by grpc.
       */
      SERVER_PERSISTENT_INSTANCE_BY_GRPC("supportPersistentInstanceByGrpc", "support persistent instance by grpc",
              AbilityMode.SERVER),
      
      /**
       * For fuzzy watch naming or config.
       */
      SERVER_FUZZY_WATCH("fuzzyWatch", "Server whether support fuzzy watch service or config", AbilityMode.SERVER),
      
      /**
       * For Distributed Lock.
       */
      SERVER_DISTRIBUTED_LOCK("lock", "Server whether support distributed lock", AbilityMode.SERVER),
      
      /**
       * For AI module MCP registry.
       */
      SERVER_MCP_REGISTRY("mcp", "Server whether support release mcp server and register endpoint for mcp server",
              AbilityMode.SERVER),
      
      /**
       * For AI module Agent & Agent Card registry.
       */
      SERVER_AGENT_REGISTRY("agent", "Server whether support release agent server and register endpoint for agent server",
              AbilityMode.SERVER),
      
      /**
       * For fuzzy watch naming or config.
       */
      SDK_CLIENT_FUZZY_WATCH("fuzzyWatch", "Client whether support fuzzy watch service or config",
              AbilityMode.SDK_CLIENT),
      
      /**
       * For Distributed Lock.
       */
      SDK_CLIENT_DISTRIBUTED_LOCK("lock", "Client whether support distributed lock", AbilityMode.SDK_CLIENT),
      
      /**
       * For AI module MCP registry.
       */
      SDK_MCP_REGISTRY("mcp", "Client whether support release mcp server and register endpoint for mcp server",
              AbilityMode.SDK_CLIENT),
      
      /**
       * For AI module Agent & Agent Card registry.
       */
      SDK_AGENT_REGISTRY("agent", "Client whether support release agent server and register endpoint for agent server",
              AbilityMode.SDK_CLIENT),
      
      /**
       * For Test temporarily.
       */
      CLUSTER_CLIENT_TEST_1("test_1", "just for junit test", AbilityMode.CLUSTER_CLIENT);
      
      /**
       * the name of a certain ability.
       */
      private final String keyName;
      
      /**
       * description or comment about this ability.
       */
      private final String description;
      
      /**
       * ability mode, which endpoint hold this ability.
       */
      private final AbilityMode mode;
      
      AbilityKey(String keyName, String description, AbilityMode mode) {
          this.keyName = keyName;
          this.description = description;
          this.mode = mode;
      }
      
      public String getName() {
          return keyName;
      }
      
      public String getDescription() {
          return description;
      }
      
      public AbilityMode getMode() {
          return mode;
      }
      
      /**
       * All key set.
       */
      private static final Map<AbilityMode, Map<String, AbilityKey>> ALL_ABILITIES = new HashMap<>();
      
      /**
       * Get all keys.
       *
       * @return all keys
       */
      public static Collection<AbilityKey> getAllValues(AbilityMode mode) {
          return Collections.unmodifiableCollection(ALL_ABILITIES.get(mode).values());
      }
      
      /**
       * Get all names.
       *
       * @return all names
       */
      public static Collection<String> getAllNames(AbilityMode mode) {
          return Collections.unmodifiableCollection(ALL_ABILITIES.get(mode).keySet());
      }
      
      /**
       * Whether contains this name.
       *
       * @param name key name
       * @return whether contains
       */
      public static boolean isLegalKey(AbilityMode mode, String name) {
          return ALL_ABILITIES.get(mode).containsKey(name);
      }
      
      /**
       * Map the string key to enum.
       *
       * @param abilities map
       * @return enum map
       */
      public static Map<AbilityKey, Boolean> mapEnum(AbilityMode mode, Map<String, Boolean> abilities) {
          if (abilities == null || abilities.isEmpty()) {
              return Collections.emptyMap();
          }
          return abilities.entrySet().stream().filter(entry -> isLegalKey(mode, entry.getKey()))
                  .collect(Collectors.toMap((entry) -> getEnum(mode, entry.getKey()), Map.Entry::getValue));
      }
      
      /**.
       * Map the string key to enum
       *
       * @param abilities map
       * @return enum map
       */
      public static Map<String, Boolean> mapStr(Map<AbilityKey, Boolean> abilities) {
          if (abilities == null || abilities.isEmpty()) {
              return Collections.emptyMap();
          }
          return abilities.entrySet().stream()
                  .collect(Collectors.toMap((entry) -> entry.getKey().getName(), Map.Entry::getValue));
      }
      
      /**.
       * getter to obtain enum
       *
       * @param key string key
       * @return enum
       */
      public static AbilityKey getEnum(AbilityMode mode, String key) {
          return ALL_ABILITIES.get(mode).get(key);
      }
      
      static {
          // check for developer
          // ensure that name filed is unique under a AbilityMode
          try {
              for (AbilityKey value : AbilityKey.values()) {
                  AbilityMode mode = value.getMode();
                  Map<String, AbilityKey> map = ALL_ABILITIES.getOrDefault(mode, new HashMap<>());
                  AbilityKey previous = map.putIfAbsent(value.getName(), value);
                  if (previous != null) {
                      throw new IllegalStateException(
                              "Duplicate key name field " + value + " and " + previous + " under mode: " + mode);
                  }
                  ALL_ABILITIES.put(mode, map);
              }
          } catch (Throwable t) {
              // for developer checking
              t.printStackTrace();
          }
      }
  }
  