# -*- coding: utf-8 -*-
# !/usr/bin/env python

# 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 ENDPOINT.
"""
import copy
import json
import logging
import uuid

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

_logger = logging.getLogger(__name__)


class EndpointClient(BceBaseClient):
    """

       Endpoint base sdk client
    """

    prefix = b'/v1'
    path = b'/endpoint'

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

    @staticmethod
    def _generate_default_client_token():
        """

        default client token by uuid1
        """
        return uuid.uuid1()

    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, EndpointClient.prefix + path, body, headers,
                                            params)

    def list_services(self, config=None):
        """

        return all services
        """
        path = EndpointClient.path + b'/publicService'
        return self._send_request(http_methods.GET, path, config=config)

    def create_endpoint(self, vpc_id, subnet_id, name, service, billing, bandwidth, 
                        description=None, ip_address=None, tags=None, resource_group_id=None,
                        client_token=None, config=None):
        """

        The method of endpoint to be created.

        :param vpc_id:
            vpc id
        :type vpc_id: str

        :param subnet_id:
            subnet id
        :type subnet_id: str

        :param name:
            name
        :type name: str

        :param service:
            service
        :type service: str

        :param billing:
           order_configuration
        :type billing:Billing

        :param bandwidth:
            The bandwidth of endpoint.
        :type bandwidth: int

        :param ip_address:
            ip_address ipv4 address
        :type ip_address: str

        :param description:
            description .
        :type description: string

        :param tags:
            The list of tags to be bound.
        :type tags: list

        :param resource_group_id:
            The id of resource group.
        :type resource_group_id: string

        :param client_token:
            An ASCII string whose length is less than 64.
            The request will be idempotent if clientToken is provided.
            If the clientToken is not specified by the user, a random String
            generated by default algorithm will be used.
        :type client_token: string
        """
        if client_token is None:
            client_token = self._generate_default_client_token()
        params = {
            b'clientToken': client_token
        }

        body = {
            "vpcId": vpc_id,
            "subnetId": subnet_id,
            "name": name,
            "service": service,
            "bandwidth": bandwidth,
            "billing": {
                "paymentTiming": billing.payment_timing
            }
        }
        if description is not None:
            body['description'] = description
        if ip_address is not None:
            body['ipAddress'] = ip_address
        if tags is not None:
            body['tags'] = tags
        if resource_group_id is not None:
            body['resourceGroupId'] = resource_group_id
        return self._send_request(http_methods.POST, EndpointClient.path, body=json.dumps(body), params=params,
                                  config=config)

    def delete_endpoint(self, endpoint_id, client_token=None, config=None):
        """

        release endpoint

        :param endpoint_id:
            The id of endpoint.
        :type endpoint_id: string

        :param client_token:
            An ASCII string whose length is less than 64.
            The request will be idempotent if clientToken is provided.
            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 = EndpointClient.path + b'/' + compat.convert_to_bytes(endpoint_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)

    def list_endpoints(self, vpc_id, name=None, ip_address=None, status=None, subnet_id=None, service=None, marker=None,
                       max_keys=None, config=None):
        """

        return all endpoint about vpc

        :param vpc_id:
            vpc id
        :type vpc_id:string

        :param name:
            name
        :type name:string

        :param ip_address:
            ip address
        :type ip_address:string

        :param status:
            status
        :type status:string

        :param subnet_id:
            subnet id
        :type subnet_id:string

        :param service:
            service
        :type service:string

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

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        params = {b'vpcId': vpc_id}
        if name is not None:
            params[b'name'] = name
        if ip_address is not None:
            params[b'ipAddress'] = ip_address
        if status is not None:
            params[b'status'] = status
        if subnet_id is not None:
            params[b'subnetId'] = subnet_id
        if service is not None:
            params[b'service'] = service

        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, EndpointClient.path, params=params, config=config)

    def get_endpoint(self, endpoint_id, config=None):
        """

        Get the detail information of  endpoint.

        :param endpoint_id:
            The id of endpoint.
        :type endpoint_id: string

        :param config:
        :type config: baidubce.BceClientConfiguration

        :return:
        :rtype baidubce.bce_response.BceResponse
        """
        path = EndpointClient.path + b'/' + compat.convert_to_bytes(endpoint_id)

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

    def update_endpoint(self, endpoint_id, name=None, description=None, client_token=None, config=None):
        """

        The method of endpoint to be update.

        :param endpoint_id: endpoint id
        :type endpoint_id: str

        :param name: endpoint name
        :type name: str

        :param description: the description of endpoint
        :type description: str

        :param client_token:
            An ASCII string whose length is less than 64.
            The request will be idempotent if clientToken is provided.
            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 = EndpointClient.path + b'/' + compat.convert_to_bytes(endpoint_id)

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

        body = {}
        if description is not None:
            body['description'] = description
        if name is not None:
            body['name'] = name

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

    def update_endpoint_sg(self, endpoint_id, security_group_list, action=b'bindSg', client_token=None, config=None):
        """

        The method of endpoint's security group to be update.

        :param endpoint_id: endpoint id
        :type endpoint_id: str

        :param security_group_list: the id list of security group to be bind with.
        :type security_group_list: list

        :param name: action
        :type name: str

        :param client_token:
            An ASCII string whose length is less than 64.
            The request will be idempotent if clientToken is provided.
            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 = EndpointClient.path + b'/' + compat.convert_to_bytes(endpoint_id)

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

        body = {
            "securityGroupIds": security_group_list
        }

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

    def update_endpoint_enterprise_sg(self, endpoint_id, enterprise_sg_list,
                                      action=b'bindEsg', client_token=None, config=None):
        """

        The method of endpoint's enterprise security group to be update.

        :param endpoint_id: endpoint id
        :type endpoint_id: str

        :param enterprise_sg_list: the id list of enterprise security group to be bind.
        :type enterprise_sg_list: list

        :param action: action
        :type action: str

        :param client_token:
            An ASCII string whose length is less than 64.
            The request will be idempotent if clientToken is provided.
            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 = EndpointClient.path + b'/' + compat.convert_to_bytes(endpoint_id)

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

        body = {
            'enterpriseSecurityGroupIds': enterprise_sg_list
        }

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