# -*- coding: utf-8 -*-

# Copyright (c) 2020 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 EIP.
"""

import copy
import json
import logging
import uuid

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

_logger = logging.getLogger(__name__)


class EipBpClient(BceBaseClient):
    """
    EIP_BP sdk client
    """
    version = b'/v1'
    prefix = b'/eipbp'

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

    @required(bandwidth_in_mbps=int)
    def create_eip_bp(self, eip, eip_group_Id, bandwidth_in_mbps, name=None, autoReleaseTime=None,
                      client_token=None, config=None):
        """
        Create an eip_bp with the specified options.

        :type eip: string
        :param eip: the eip address that the eip_bp attach.
        Param "eip" and "eip_group_Id" will has only one param take effect.

        :type eip_group_Id: string
        :param eip_group_Id: the eipgroupId that the eip_bp attach.
        Param "eip" and "eip_group_Id" will has only one param take effect.

        :type bandwidth_in_mbps: int
        :param bandwidth_in_mbps: the bandwidth of eip_bp in Mbps.

        :type name: string
        :param name:the name of eipbp. The optional parameter.

        :type auto_release_time: string (UTC format,like yyyy:mm:ddThh:mm:ssZ)
        :param autoReleaseTime: the autoReleaseTime of eipbp. The optional parameter.

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

        :type config: baidubce.BceClientConfiguration
        :param config:

        :return: created eip_bp id, for example,{"id":"bw-xxxxxxxx"}
        """
        body = {
            'bandwidthInMbps': bandwidth_in_mbps
        }
        if eip is None and eip_group_Id is None:
            raise ValueError(b"eip and eip_group_Id can't be none at the same time.")

        if eip is not None:
            body['eip'] = eip
        if eip_group_Id is not None:
            body['eipGroupId'] = eip_group_Id
        if name is not None:
            body['name'] = name
        if autoReleaseTime is not None:
            body['autoReleaseTime'] = autoReleaseTime

        path = self._get_path()
        if client_token is None:
            client_token = self._generate_default_client_token()
        params = {
            b'clientToken': client_token
        }

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

    @required(id=str, new_bandwidth_in_mbps=int)
    def resize_eip_bp(self, id, new_bandwidth_in_mbps, client_token=None,
                      config=None):
        """
        Resizing eip_bp

        :type id: string
        :param id: eip_bp's id to be resized

        :type new_bandwidth_in_mbps: int
        :param new_bandwidth_in_mbps: specify new bandwidth in Mbps for eip_bp

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

        :type config: baidubce.BceClientConfiguration
        :param config:

        :return: BceResponse
        """
        body = {
            'bandwidthInMbps': new_bandwidth_in_mbps
        }
        path = utils.append_uri(self._get_path(), id)
        if client_token is None:
            client_token = self._generate_default_client_token()
        params = {
            b'resize': b'',
            b'clientToken': client_token
        }
        return self._send_request(http_methods.PUT, path, params=params,
                                  body=json.dumps(body), config=config)

    @required(id=str)
    def get_eip_bp_detail(self, id, config=None):
        """
        get eip_bp's detail owned by the authenticated user and givened eip_bp_id.

        :type id: string
        :param eip: eip_bp's id.

        :type config: baidubce.BceClientConfiguration
        :param config:

        :return: detail of eip_bp, for example:
                {
                    "autoReleaseTime": "2020-05-30T06:46:44Z",
                    "name": "EIP_BP1588821183401",
                    "instanceId": "ip-9340430e",
                    "createTime": "2020-05-07T03:13:03Z",
                    "id": "bw-5fb3ce39",
                    "eips": [
                        "100.88.9.120"
                    ],
                    "instanceBandwidthInMbps": 1,
                    "bandwidthInMbps": 2,
                    "bindType": "eip"
                }
        """

        path = utils.append_uri(self._get_path(), id)
        return self._send_request(http_methods.GET, path, params=None,
                                  config=config)

    def list_eip_bps(self, id=None, name=None, bind_type=None,
                     marker=None, max_keys=1000, config=None):
        """
        get a list of eip_bp owned by the authenticated user and specified
        conditions. we can Also get a single eip_bp function  through this
        interface by eip_bp condition

        :type id: string
        :param id: eip_bp 's id conditions

        :type name: string
        :param name: eip_bp 's name condition

        :type bind_type: string
        :param bind_type: eip_bp 's bind_type condition, 'eip' or 'eipgroup'

        :type marker: string
        :param marker: The optional parameter marker specified in the original
         request to specify where in the results to begin listing.

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

        :type config: baidubce.BceClientConfiguration
        :param config:

        :return: list of eip_bp model, for example:
                {
                    "marker": "bw-5fb3ce39",
                    "maxKeys": 1000,
                    "nextMarker": null,
                    "bpList": [
                        {
                            "autoReleaseTime": "2020-05-30T06:46:44Z",
                            "name": "EIP_BP1588821183401",
                            "instanceId": "ip-9340430e",
                            "createTime": "2020-05-07T03:13:03Z",
                            "id": "bw-5fb3ce39",
                            "eips": [
                                "100.88.9.120"
                            ],
                            "bandwidthInMbps": 2,
                            "bindType": "eip"
                        }
                    ],
                    "isTruncated": false
                }
       """

        path = self._get_path()
        params = {}
        if id is not None:
            params[b'id'] = id
        if name is not None:
            params[b'name'] = name
        if bind_type is not None:
            params[b'bindType'] = bind_type
        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(id=str, auto_release_time=str)
    def update_eip_bp_autoReleaseTime(self, id, auto_release_time, client_token=None,
                                      config=None):
        """
        Update eip_bp's auto_release_time

        :type id: string
        :param id: eip_bp's id

        :type auto_release_time: string (UTC format,like yyyy:mm:ddThh:mm:ssZ)
        :param auto_release_time: specify auto_release_time for eip_bp

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

        :type config: baidubce.BceClientConfiguration
        :param config:

        :return: BceResponse
        """
        body = {
            'autoReleaseTime': auto_release_time
        }
        path = utils.append_uri(self._get_path(), id)
        if client_token is None:
            client_token = self._generate_default_client_token()
        params = {
            b'retime': b'',
            b'clientToken': client_token
        }
        return self._send_request(http_methods.PUT, path, params=params,
                                  body=json.dumps(body), config=config)

    @required(id=str, name=str)
    def rename_eip_bp(self, id, name, client_token=None,
                      config=None):
        """
        Update eip_bp's name

        :type id: string
        :param id: eip_bp's id

        :type name: string
        :param name: eip_bp's name

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

        :type config: baidubce.BceClientConfiguration
        :param config:

        :return: BceResponse
        """
        body = {
            'name': name
        }
        path = utils.append_uri(self._get_path(), id)
        if client_token is None:
            client_token = self._generate_default_client_token()
        params = {
            b'rename': b'',
            b'clientToken': client_token
        }
        return self._send_request(http_methods.PUT, path, params=params,
                                  body=json.dumps(body), config=config)

    @required(id=str)
    def release_eip_bp(self, id, client_token=None, config=None):
        """
        release the eip_bp(delete operation)

        :type id: string
        :param id: eip_bp's id to be released

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

        :type config: baidubce.BceClientConfiguration
        :param config:

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

    @staticmethod
    def _generate_default_client_token():
        """
        default client token by uuid1
        """
        return uuid.uuid1()

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

    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:

        :type config: baidubce.BceClientConfiguration
        :param config:

        :param body_parser:

        :return: baidubce.BceResponse
        """
        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)
