# Petale - Simple App as Key/Value Storage Interface
# Copyright (C) 2017  Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import hashlib
import logging
from functools import wraps

DEFAULT_HASH_ALGO = 'sha1'


def logit(func):
    @wraps(func)
    def wrapper(self, request, *args, **kwargs):
        logger = logging.getLogger('petale')
        req_url = '%s %s %s' % (request.method, request.path, request.GET.urlencode())
        logger.info(req_url, extra={'request_url': req_url})
        req_headers = ''.join(['%s: %s | ' % (k, v) for k, v in request.META.items() if k.isupper()])
        logger.debug('Request Headers: %s', req_headers, extra={'request_headers': req_headers})
        response = func(self, request, *args, **kwargs)
        resp_headers = ''.join(['%s: %s | ' % (k, v) for k, v in response.items()])
        logger.debug('Response Headers: %s', resp_headers, extra={'response_headers': resp_headers})
        if hasattr(response, 'data'):
            logger.debug('Response Data: %r', response.data, extra={'response_body': response.data})
        logger.debug(
            'Response Status Code: %s',
            response.status_code,
            extra={'response_status_code': response.status_code},
        )
        return response

    return wrapper


def etag(stream):
    # f must be a Django file object
    digest = hashlib.new(DEFAULT_HASH_ALGO)
    if hasattr(stream, 'chunks'):
        for chunk in stream.chunks():
            digest.update(chunk)
    elif hasattr(stream, 'isdecimal'):
        digest.update(stream.encode('utf-8'))
    else:
        digest.update(stream)
    return '"%s:%s"' % (DEFAULT_HASH_ALGO, digest.hexdigest())


class StreamingHash:
    def __init__(self, readable, hash_algo=DEFAULT_HASH_ALGO):
        self.readable = readable
        self.hash_algo = hash_algo
        self.digest = hashlib.new(hash_algo)
        self.size = 0

    def read(self, n=-1):  # pylint: disable=C0103
        buf = self.readable.read(n)
        self.size += len(buf)
        self.digest.update(buf)
        return buf

    def hexdigest(self):
        return self.digest.hexdigest()

    def etag(self):
        return '"%s:%s"' % (self.hash_algo, self.hexdigest())
