/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 */

/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you 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.
 */

/*
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */

package org.opensearch.discovery.ec2;

import org.opensearch.common.settings.Setting;
import org.opensearch.common.settings.Setting.Property;
import org.opensearch.common.unit.TimeValue;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;

interface AwsEc2Service extends Closeable {

    Setting<Boolean> AUTO_ATTRIBUTE_SETTING = Setting.boolSetting("cloud.node.auto_attributes", false, Property.NodeScope);

    class HostType {
        public static final String PRIVATE_IP = "private_ip";
        public static final String PUBLIC_IP = "public_ip";
        public static final String PRIVATE_DNS = "private_dns";
        public static final String PUBLIC_DNS = "public_dns";
        public static final String TAG_PREFIX = "tag:";
    }

    /**
     * discovery.ec2.host_type: The type of host type to use to communicate with other instances.
     * Can be one of private_ip, public_ip, private_dns, public_dns or tag:XXXX where
     * XXXX refers to a name of a tag configured for all EC2 instances. Instances which don't
     * have this tag set will be ignored by the discovery process. Defaults to private_ip.
     */
    Setting<String> HOST_TYPE_SETTING = new Setting<>(
        "discovery.ec2.host_type",
        HostType.PRIVATE_IP,
        Function.identity(),
        Property.NodeScope
    );
    /**
     * discovery.ec2.any_group: If set to false, will require all security groups to be present for the instance to be used for the
     * discovery. Defaults to true.
     */
    Setting<Boolean> ANY_GROUP_SETTING = Setting.boolSetting("discovery.ec2.any_group", true, Property.NodeScope);
    /**
     * discovery.ec2.groups: Either a comma separated list or array based list of (security) groups. Only instances with the provided
     * security groups will be used in the cluster discovery. (NOTE: You could provide either group NAME or group ID.)
     */
    Setting<List<String>> GROUPS_SETTING = Setting.listSetting(
        "discovery.ec2.groups",
        new ArrayList<>(),
        s -> s.toString(),
        Property.NodeScope
    );
    /**
     * discovery.ec2.availability_zones: Either a comma separated list or array based list of availability zones. Only instances within
     * the provided availability zones will be used in the cluster discovery.
     */
    Setting<List<String>> AVAILABILITY_ZONES_SETTING = Setting.listSetting(
        "discovery.ec2.availability_zones",
        Collections.emptyList(),
        s -> s.toString(),
        Property.NodeScope
    );
    /**
     * discovery.ec2.node_cache_time: How long the list of hosts is cached to prevent further requests to the AWS API. Defaults to 10s.
     */
    Setting<TimeValue> NODE_CACHE_TIME_SETTING = Setting.timeSetting(
        "discovery.ec2.node_cache_time",
        TimeValue.timeValueSeconds(10),
        Property.NodeScope
    );

    /**
     * discovery.ec2.tag.*: The ec2 discovery can filter machines to include in the cluster based on tags (and not just groups).
     * The settings to use include the discovery.ec2.tag. prefix. For example, setting discovery.ec2.tag.stage to dev will only filter
     * instances with a tag key set to stage, and a value of dev. Several tags set will require all of those tags to be set for the
     * instance to be included.
     */
    Setting.AffixSetting<List<String>> TAG_SETTING = Setting.prefixKeySetting(
        "discovery.ec2.tag.",
        key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Property.NodeScope)
    );

    /**
     * Builds then caches an {@code AmazonEC2} client using the current client
     * settings. Returns an {@code AmazonEc2Reference} wrapper which should be
     * released as soon as it is not required anymore.
     */
    AmazonEc2ClientReference client();

    /**
     * Updates the settings for building the client and releases the cached one.
     * Future client requests will use the new settings to lazily built the new
     * client.
     *
     * @param clientSettings the new refreshed settings
     */
    void refreshAndClearCache(Ec2ClientSettings clientSettings);
}
