# Copyright 2017-present Adtran, Inc.
#
# 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.

import json

import structlog
import treq
from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.internet.error import ConnectionClosed, ConnectionDone, ConnectionLost

log = structlog.get_logger()


class RestInvalidResponseCode(Exception):
    def __init__(self, message, url, code):
        super(RestInvalidResponseCode, self).__init__(message)
        self.url = url
        self.code = code


class AdtranRestClient(object):
    """
    Performs Adtran RESTCONF requests
    """
    # HTTP shortcuts
    HELLO_URI = '/restconf/adtran-hello:hello'

    REST_GET_REQUEST_HEADER = {'User-Agent': 'Adtran RESTConf',
                               'Accept': ['application/json']}

    REST_POST_REQUEST_HEADER = {'User-Agent': 'Adtran RESTConf',
                                'Content-Type': 'application/json',
                                'Accept': ['application/json']}

    REST_PATCH_REQUEST_HEADER = REST_POST_REQUEST_HEADER
    REST_PUT_REQUEST_HEADER = REST_POST_REQUEST_HEADER
    REST_DELETE_REQUEST_HEADER = REST_GET_REQUEST_HEADER

    HTTP_OK = 200
    HTTP_CREATED = 201
    HTTP_ACCEPTED = 202
    HTTP_NON_AUTHORITATIVE_INFORMATION = 203
    HTTP_NO_CONTENT = 204
    HTTP_RESET_CONTENT = 205
    HTTP_PARTIAL_CONTENT = 206
    HTTP_NOT_FOUND = 404

    _valid_methods = {'GET', 'POST', 'PATCH', 'DELETE'}
    _valid_results = {'GET': [HTTP_OK, HTTP_NO_CONTENT],
                      'POST': [HTTP_OK, HTTP_CREATED, HTTP_NO_CONTENT],
                      'PUT': [HTTP_OK, HTTP_CREATED, HTTP_NO_CONTENT],
                      'PATCH': [HTTP_OK],
                      'DELETE': [HTTP_OK, HTTP_ACCEPTED, HTTP_NO_CONTENT, HTTP_NOT_FOUND]
                      }

    for _method in _valid_methods:
        assert _method in _valid_results  # Make sure we have a results entry for each supported method

    def __init__(self, host_ip, port, username='', password='', timeout=10):
        """
        REST Client initialization

        :param host_ip: (string) IP Address of Adtran Device
        :param port: (int) Port number
        :param username: (string) Username for credentials
        :param password: (string) Password for credentials
        :param timeout: (int) Number of seconds to wait for a response before timing out
        """
        self._ip = host_ip
        self._port = port
        self._username = username
        self._password = password
        self._timeout = timeout

    def __str__(self):
        return "AdtranRestClient {}@{}:{}".format(self._username, self._ip, self._port)

    @inlineCallbacks
    def request(self, method, uri, data=None, name='', timeout=None, is_retry=False,
                suppress_error=False):
        """
        Send a REST request to the Adtran device

        :param method: (string) HTTP method
        :param uri: (string) fully URL to perform method on
        :param data: (string) optional data for the request body
        :param name: (string) optional name of the request, useful for logging purposes
        :param timeout: (int) Number of seconds to wait for a response before timing out
        :param is_retry: (boolean) True if this method called recursively in order to recover
                                   from a connection loss. Can happen sometimes in debug sessions
                                   and in the real world.
        :param suppress_error: (boolean) If true, do not output ERROR message on REST request failure
        :return: (dict) On success with the proper results
        """
        log.debug('request', method=method, uri=uri, data=data, retry=is_retry)

        if method.upper() not in self._valid_methods:
            raise NotImplementedError("REST method '{}' is not supported".format(method))

        url = 'http://{}:{}{}{}'.format(self._ip, self._port,
                                        '/' if uri[0] != '/' else '',
                                        uri)
        response = None
        timeout = timeout or self._timeout

        try:
            if method.upper() == 'GET':
                response = yield treq.get(url,
                                          auth=(self._username, self._password),
                                          timeout=timeout,
                                          headers=self.REST_GET_REQUEST_HEADER)
            elif method.upper() == 'POST' or method.upper() == 'PUT':
                response = yield treq.post(url,
                                           data=data,
                                           auth=(self._username, self._password),
                                           timeout=timeout,
                                           headers=self.REST_POST_REQUEST_HEADER)
            elif method.upper() == 'PATCH':
                response = yield treq.patch(url,
                                            data=data,
                                            auth=(self._username, self._password),
                                            timeout=timeout,
                                            headers=self.REST_PATCH_REQUEST_HEADER)
            elif method.upper() == 'DELETE':
                response = yield treq.delete(url,
                                             auth=(self._username, self._password),
                                             timeout=timeout,
                                             headers=self.REST_DELETE_REQUEST_HEADER)
            else:
                raise NotImplementedError("REST method '{}' is not supported".format(method))

        except NotImplementedError:
            raise

        except (ConnectionDone, ConnectionLost) as e:
            if is_retry:
                raise
            returnValue(self.request(method, uri, data=data, name=name,
                                     timeout=timeout, is_retry=True))

        except ConnectionClosed:
            returnValue(ConnectionClosed)

        except Exception as e:
            log.exception("rest-request", method=method, url=url, name=name, e=e)
            raise

        if response.code not in self._valid_results[method.upper()]:
            message = "REST {} '{}' request to '{}' failed with status code {}".format(method, name,
                                                                                       url, response.code)
            if not suppress_error:
                log.error(message)
            raise RestInvalidResponseCode(message, url, response.code)

        if response.code in {self.HTTP_NO_CONTENT, self.HTTP_NOT_FOUND}:
            returnValue(None)

        else:
            # TODO: May want to support multiple body encodings in the future

            headers = response.headers
            type_key = 'content-type'
            type_val = 'application/json'

            if not headers.hasHeader(type_key) or type_val not in headers.getRawHeaders(type_key, []):
                raise Exception("REST {} '{}' request response from '{}' was not JSON",
                                method, name, url)

            content = yield response.content()
            try:
                result = json.loads(content)

            except Exception as e:
                log.exception("json-decode", method=method, url=url, name=name,
                              content=content, e=e)
                raise

            returnValue(result)
