# Copyright (c) 2014 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 HAVIP.
"""

import copy
import json
import logging
import uuid

from baidubce import bce_base_client
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
from baidubce import compat

_logger = logging.getLogger(__name__)


class HavipClient(bce_base_client.BceBaseClient):
    """
    Route base sdk client
    """
    prefix = b'/v1'

    def __init__(self, config=None):
        bce_base_client.BceBaseClient.__init__(self, config)

    def _merge_config(self, config=None):
        """
        :param config:
        :type config: baidubce.BceClientConfiguration
        :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):
        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, HavipClient.prefix + path, body, headers, params)

    @required(name=(bytes, str),
              subnet_id=(bytes, str),
              private_ip_address=(bytes, str),
              description=(bytes, str))
    def create_havip(self, name, subnet_id, private_ip_address,
                     description="", client_token=None, config=None):
        """
        Create a havip with the specified options.

        :param name:
            The name of havip.
        :type name: string

        :param subnet_id:
            The subnet ID to which the havip belongs.
        :type subnet_id: string

        :param private_ip_address:
            The private_ip_address of the havip
        :type private_ip_address: string

        :param description:
            The option param to describe the havip.
        :type description: string

        :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 config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip'
        params = {}

        if client_token is None:
            params[b'clientToken'] = generate_client_token()
        else:
            params[b'clientToken'] = client_token

        body = {
            'name': compat.convert_to_string(name),
            'subnetId': compat.convert_to_string(subnet_id),
            'privateIpAddress': compat.convert_to_string(private_ip_address),
            'description': compat.convert_to_string(description)
        }

        return self._send_request(http_methods.POST, path, body=json.dumps(body), params=params,
                                  config=config)

    def get_havip_detail_list(self, vpc_id=None, marker=None, max_keys=None, config=None):
        """
        Get the detail information of havip list.

        :param vpc_id:
            the vpc id to which the havip belongs
        :type vpc_id: string

        :param marker:
            批量获取列表的查询的起始位置，是一个由系统生成的字符串
        :type marker: string

        :param max_keys:
            每页包含的最大数量，最大数量不超过1000，缺省值为1000
        :type max_keys: int

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip'
        params = {}
        if vpc_id is not None:
            params[b'vpcId'] = vpc_id
        if marker is not None:
            params[b'marker'] = marker
        if max_keys is not None:
            params[b'maxKeys'] = max_keys

        return self._send_request(http_methods.GET, path, params=params, config=config)

    @required(havip_id=(bytes, str))
    def delete_havip(self, havip_id, client_token=None, config=None):
        """
        Delete the  specific havip.

        :param havip_id:
            The id of the specified havip.
        :type havip_id: string

        :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 config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip/%s' % compat.convert_to_bytes(havip_id)
        params = {}
        if client_token is None:
            params[b'clientToken'] = generate_client_token()
        else:
            params[b'clientToken'] = client_token
        return self._send_request(http_methods.DELETE, path, params=params, config=config)

    @required(name=(bytes, str),
              havip_id=(bytes, str),
              description=(bytes, str))
    def update_havip(self, name, havip_id, description="", 
                     client_token=None, config=None):
        """
        Update a havip with the specified options.

        :param name:
            The name of the havip to be updated.
        :type route_rule_id: string

        :param havip_id:
            The id of the specified havip.
        :type havip_id: string

        :param description:
            The option param to describe the route rule.
        :type description: string

        :param action:
            Action.
        :type action: string, default: modifyAttribute

        :param version:
            API version.
        :type version: string

        :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 config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip/%s' % compat.convert_to_bytes(havip_id)
        params = {
            b'modifyAttribute': None
        }

        if client_token is None:
            params[b'clientToken'] = generate_client_token()
        else:
            params[b'clientToken'] = client_token

        body = {
            'name': compat.convert_to_string(name),
            'description': compat.convert_to_string(description)
        }

        return self._send_request(http_methods.PUT, path, body=json.dumps(body), params=params, config=config)

    @required(havip_id=(bytes, str))
    def get_havip_detail(self, havip_id, config=None):
        """
        Get the detail information of a specific havip.

        :param havip_id:
            The id of the havip.
        :type havip_id: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip/%s' % compat.convert_to_bytes(havip_id)
        params = {}

        return self._send_request(http_methods.GET, path, params=params, config=config)

    @required(instance_ids=list,
              instance_type=(bytes, str),
              havip_id=(bytes, str))
    def havip_attach_instance(self, instance_ids, instance_type, havip_id, client_token=None, config=None):
        """
        Attach instances to havip.

        :param instance_ids:
            the instance ids of havip binding
        :type instance_ids: list

        :param instance_type:
            Binding instance type (SERVER or ENI)
        :type instance_type: string

        :param havip_id:
            The id of the specified havip.
        :type havip_id: string

        :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 config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip/%s' % compat.convert_to_bytes(havip_id)
        params = {
            b'attach': None
        }

        if client_token is None:
            params[b'clientToken'] = generate_client_token()
        else:
            params[b'clientToken'] = client_token

        body = {
            'instanceIds': instance_ids,
            'instanceType': compat.convert_to_string(instance_type)
        }

        return self._send_request(http_methods.PUT, path, body=json.dumps(body), params=params, config=config)

    @required(instance_ids=list,
              instance_type=(bytes, str),
              havip_id=(bytes, str))
    def havip_detach_instance(self, instance_ids, instance_type, havip_id, client_token=None, config=None):
        """
        havip detach instance.

        :param instance_ids:
            the instance ids of havip binding
        :type instance_ids: list

        :param instance_type:
            Binding instance type (SERVER or ENI)
        :type instance_type: string

        :param havip_id:
            The id of the specified havip.
        :type havip_id: string

        :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 config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip/%s' % compat.convert_to_bytes(havip_id)

        params = {b'detach': None}

        if client_token is None:
            params[b'clientToken'] = generate_client_token()
        else:
            params[b'clientToken'] = client_token

        body = {
            'instanceIds': instance_ids,
            'instanceType': compat.convert_to_string(instance_type)
        }

        return self._send_request(http_methods.PUT, path, body=json.dumps(body), params=params, config=config)

    @required(havip_id=(bytes, str),
              public_ip_address=(bytes, str))
    def havip_bind_public_ip(self, havip_id, public_ip_address, client_token=None, config=None):
        """
        havip bind public_ip.

        :param havip_id:
            The id of the specified havip.
        :type havip_id: string

        :param public_ip_address:
            The public IP address to bind.
        :type public_ip_address: string

        :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 config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip/%s' % compat.convert_to_bytes(havip_id)
        params = {
            b'bindPublicIp': None
        }

        if client_token is None:
            params[b'clientToken'] = generate_client_token()
        else:
            params[b'clientToken'] = client_token

        body = {
            'publicIpAddress': compat.convert_to_string(public_ip_address)
        }

        return self._send_request(http_methods.PUT, path, body=json.dumps(body), params=params, config=config)

    @required(havip_id=(bytes, str))
    def havip_unbind_public_ip(self, havip_id, client_token=None, config=None):
        """
        havip unbind public_ip.

        :param havip_id:
            The id of the specified havip.
        :type havip_id: string

        :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 config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = b'/havip/%s' % compat.convert_to_bytes(havip_id)
        params = {
            b'unbindPublicIp': None
        }

        if client_token is None:
            params[b'clientToken'] = generate_client_token()
        else:
            params[b'clientToken'] = client_token

        return self._send_request(http_methods.PUT, path, params=params, config=config)

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