# Copyright (c) 2023 Baidu.com, Inc. 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.

"""
This module provides a client class for Et Gateway.
"""

import copy
import json
import uuid

from baidubce import bce_base_client
from baidubce import compat
from baidubce import utils
from baidubce.auth import bce_v1_signer
from baidubce.http import bce_http_client
from baidubce.http import handler
from baidubce.http import http_methods
from baidubce.utils import required


class EtGatewayClient(bce_base_client.BceBaseClient):
    """
    Et Gateway Client
    """
    version = b'/v1'
    prefix = b'/etGateway'
    health_check = b'/healthCheck'

    def __init__(self, config=None):
        """
        :type config: baidubce.BceClientConfiguration
        """
        bce_base_client.BceBaseClient.__init__(self, config)

    def _merge_config(self, config):
        """
        :type config: baidubce.BceClientConfiguration
        :param config:
        :return:
        """
        if config is None:
            return self.config
        else:
            new_config = copy.copy(self.config)
            new_config.merge_non_none_values(config)
            return new_config

    def _send_request(self, http_method, path,
                      body=None, headers=None, params=None,
                      config=None, body_parser=None):
        """
        :param http_method:
        :param path:
        :param body:
        :param headers:
        :param params:
        :param config:
        :param body_parser:
        :return:
        """
        config = self._merge_config(config)
        if body_parser is None:
            body_parser = handler.parse_json
        if headers is None:
            headers = {
                b'Accept': b'*/*', b'Content-Type':
                b'application/json;charset=utf-8'
            }

        return bce_http_client.send_request(
            config, bce_v1_signer.sign, [handler.parse_error, body_parser],
            http_method, path, body, headers, params)

    @required(name=(bytes, str),
              vpc_id=(bytes, str),
              speed=(int, long))
    def create_et_gateway(self, name, vpc_id, speed, et_id=None, channel_id=None,
                          local_cidrs=None, client_token=None, description=None, config=None):
        """
        Create a ET Gateway.

        :param name:
            the name of ET Gateway
        :type name: string

        :param vpc_id:
            the id of VPC
        :type vpc_id: string

        :param speed:
            the bandwidth of ET Gateway
        :type speed: int

        :param et_id:
            the id of ET
        :type et_id: string

        :param channel_id:
            the id of Channel
        :type channel_id: string

        :param local_cidrs:
            the list of CIDRs
        :type local_cidrs: list

        :param client_token:
            If the clientToken is not specified by the user, a random String
            generated by default algorithm will be used.
        :type client_token: string

        :param description:
            the description of ET Gateway
        :type description: string

        :type config:
            baidubce.BceClientConfiguration
        :param config:

        :return: created ET Gateway ID
        """

        path = self._get_path()
        params = {}
        if client_token is None:
            params[b'clientToken'] = generate_client_token()
        else:
            params[b'clientToken'] = client_token

        body = {
            'name': name,
            'vpcId': vpc_id,
            'speed': speed,
        }

        if et_id is not None:
            body[b'etId'] = et_id
        if channel_id is not None:
            body[b'channelId'] = channel_id
        if local_cidrs is not None:
            body[b'localCidrs'] = local_cidrs
        if description is not None:
            body[b'description'] = description
        return self._send_request(http_methods.POST, path, body=json.dumps(body), params=params, config=config)

    @required(et_gateway_id=(bytes, str))
    def update_et_gateway(self, et_gateway_id, name=None, description=None,
                          speed=None, local_cidrs=None, client_token=None, config=None):
        """
        Update a ET Gateway.
        :param et_gateway_id:
            the id of ET Gateway
        :type et_gateway_id: string

        :param name:
            the name of ET Gateway
        :type name: string

        :param description:
            the description of ET Gateway
        :type description: string

        :param speed:
            the bandwidth of ET Gateway
        :type speed: int

        :param local_cidrs:
            the list of CIDRs
        :type local_cidrs: list

        :param client_token:
            If the clientToken is not specified by the user, a random String
        :type client_token: string

        :description:
            the description of ET Gateway
        :type description: string

        :return:
        :rtype baidubce.bce_response.BceResponse

        """

        path = utils.append_uri(self._get_path(), et_gateway_id)
        if client_token is None:
            client_token = generate_client_token()
        params = {
            b'clientToken': client_token
        }
        body = {}
        if name is not None:
            body[b'name'] = name
        if description is not None:
            body[b'description'] = description
        if speed is not None:
            body[b'speed'] = speed
        if local_cidrs is not None:
            body[b'localCidrs'] = local_cidrs
        return self._send_request(http_methods.PUT,
                                  path, body=json.dumps(body),
                                  params=params, config=config)

    @required(et_gateway_id=(bytes, str))
    def delete_et_gateway(self, et_gateway_id, client_token=None, config=None):
        """
        Delete a ET Gateway.
        :param et_gateway_id: the id of ET Gateway
        :type et_gateway_id: string

        :param client_token:
            If the clientToken is not specified by the user, a random String
        :type client_token: string

        :return:
        rtype baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(self._get_path(), et_gateway_id)
        if client_token is None:
            client_token = generate_client_token()
        params = {
            b'clientToken': client_token
        }
        return self._send_request(http_methods.DELETE,
                                  path, params=params, config=config)

    @required(et_gateway_id=(bytes, str), et_id=(bytes, str),
              action=(bytes, str), channel_id=(bytes, str))
    def bind_et(self, et_id, et_gateway_id, channel_id, local_cidrs=None, client_token=None, config=None):
        """
        Bind a ET to an ET Gateway.
        :param et_id:
            the id of ET
        :type et_id: string

        :param et_gateway_id:
            the id of ET Gateway
        :type et_gateway_id: string

        :param channel_id:
            the id of channel
        :type channel_id: string

        :param local_cidrs:
            the list of CIDRs
        :type local_cidrs: list

        :param config:
        :type config: baidubce.BceClientConfiguration

        :param client_token:
            If the clientToken is not specified by the user, a random String
        :type client_token: string

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(self._get_path(), et_gateway_id)
        if client_token is None:
            client_token = generate_client_token()
        params = {
            b'bind': None,
            b'clientToken': client_token
        }
        body = {
            'etId': et_id,
            'channelId': channel_id,
        }
        if local_cidrs is not None:
            body[b'localCidrs'] = local_cidrs
        return self._send_request(http_methods.PUT, path, body=json.dumps(body), params=params, config=config)

    @required(et_gateway_id=(bytes, str))
    def unbind_et(self, et_gateway_id, client_token=None, config=None):
        """
        Unbind a ET from an ET Gateway.
        :param et_gateway_id:
            the id of ET Gateway
        :type et_gateway_id: string

        :param client_token:
            If the clientToken is not specified by the user, a random String
        :type client_token: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """

        path = utils.append_uri(self._get_path(), et_gateway_id)
        if client_token is None:
            client_token = generate_client_token()
        param = {
            b'unbind': None,
            b'clientToken': client_token
        }
        return self._send_request(http_methods.PUT, path, params=param, config=config)

    @required(vpc_id=(bytes, str))
    def list_et_gateway(self, vpc_id, et_gateway_id=None, name=None,
                        status=None, marker=None, max_keys=None, config=None):
        """
        List ET Gateway.
        :param et_gateway_id:
            the id of ET Gateway
        :type et_gateway_id: string

        :param max_keys:
            The optional parameter to specifies the max number of
            list result to return.
            The default value is 1000.
        :type max_keys: int

        :param marker:
            The optional parameter marker specified in the original
            request to specify where in the results to begin listing.
            Together with the marker, specifies the list result which
            listing should begin. If the marker is not specified,
            the list result will listing from the first one.
        :type marker: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = self._get_path()
        param = {
            b'vpcId': vpc_id,
        }
        if et_gateway_id is not None:
            param[b'etGatewayId'] = et_gateway_id
        if name is not None:
            param[b'name'] = name
        if status is not None:
            param[b'status'] = status
        if marker is not None:
            param[b'marker'] = marker
        if max_keys is not None:
            param[b'maxKeys'] = max_keys
        return self._send_request(http_methods.GET, path, params=param, config=config)

    @required(et_gateway_id=(bytes, str))
    def get_et_gateway(self, et_gateway_id, config=None):
        """
        Get ET Gateway.
        :param et_gateway_id:
            the id of ET Gateway
        :type et_gateway_id: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(self._get_path(), et_gateway_id)
        return self._send_request(http_methods.GET, path, config=config)

    @required(et_gateway_id=(bytes, str), health_check_interval=(int, long), health_check_threshold=(int, long),
              unhealth_threshold=(int, long))
    def create_health_check(self, et_gateway_id, health_check_interval, health_check_threshold, unhealth_threshold,
                            health_check_source_ip=None, health_check_type=None, health_check_port=None,
                            auto_generate_route_rule=None, client_token=None, config=None):
        """
        Create Health Check.
        :param et_gateway_id:
            the id of ET Gateway
        :type et_gateway_id: string

        :param health_check_source_ip:
            the source ip of health check
        :type health_check_source_ip: string

        :param health_check_type:
            the type of health check
        :type health_check_type: string

        :param health_check_port:
            the port of health check
        :type health_check_port: int

        :param health_check_interval:
            the interval of health check
        :type health_check_interval: int

        :param health_check_threshold:
            the threshold of health check
        :type health_check_threshold: int

        :param unhealth_threshold:
            the unhealth threshold of health check
        :type unhealth_threshold: int

        :param auto_generate_route_rule:
            the optional parameter to specifies whether auto generate route rule
        :type auto_generate_route_rule: bool

        :param client_token:
            the optional parameter to specify a unique client token
        :type client_token: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = utils.append_uri(
            self._get_path(), et_gateway_id, self.health_check)
        if client_token is None:
            client_token = generate_client_token()
        param = {
            b'clientToken': client_token,
        }
        body = {
            b'healthCheckInterval': health_check_interval,
            b'healthThreshold': health_check_threshold,
            b'unhealthThreshold': unhealth_threshold,
        }
        if health_check_source_ip is not None:
            body[b'healthCheckSourceIp'] = health_check_source_ip
        if health_check_type is not None:
            body[b'healthCheckType'] = health_check_type
        if health_check_port is not None:
            body[b'healthCheckPort'] = health_check_port
        if auto_generate_route_rule is not None:
            body[b'autoGenerateRouteRule'] = auto_generate_route_rule
        return self._send_request(http_methods.POST, path, params=param, body=json.dumps(body), config=config)

    @staticmethod
    def _get_path(prefix=None):
        """
        :type prefix: string
        :param prefix: path prefix
        """
        if prefix is None:
            prefix = EtGatewayClient.prefix
        return utils.append_uri(EtGatewayClient.version, prefix)


def generate_client_token_by_uuid():
    """
    The default method to generate the random string for client_token
    if the optional parameter client_token is not specified by the user.

    :return:
    :rtype string
    """
    return str(uuid.uuid4())


generate_client_token = generate_client_token_by_uuid
