# -*- coding: utf-8 -*-
"""Implement geodisWS."""
import requests

from roulier.transport import Transport
from roulier.exception import CarrierError
import json
import logging
import hashlib
import time

log = logging.getLogger(__name__)


class GeodisTransportRestWs(Transport):
    """Implement Geodis Rest WS communication."""

    def get_token(self, id, timestamp, lang, hash):
        params = [id, timestamp, lang, hash]
        return ";".join(params)

    def get_hash(self, api_key, id, timestamp, lang, service, json_data):
        return hashlib.sha256(
            ";".join([api_key, id, timestamp, lang, service, json_data]).encode("utf-8")
        ).hexdigest()

    def prepare_data(self, data, login, api_key, service):
        timestamp = "%d" % (time.time() * 1000)
        lang = "fr"
        body = json.dumps(data)
        hash = self.get_hash(api_key, login, timestamp, lang, service, body)
        token = self.get_token(login, timestamp, lang, hash)
        return body, token

    def send(self, payload):
        """Call this function.

        Args:
            payload.body: JSON
            payload.header : auth
            payload.infos: { url: string, xmlns: string}
        Return:
            {
                response: (Requests.response)
                body: XML response (without soap)
                parts: empty dict // compat with WS
            }
        """
        body, token = self.prepare_data(
            payload["body"],
            payload["headers"]["login"],
            payload["headers"]["password"],
            payload["infos"]["service"],
        )

        infos = payload["infos"]
        infos["token"] = token

        response = self.send_request(body, infos)
        log.info("WS response time %s" % response.elapsed.total_seconds())
        return self.handle_response(response)

    def send_request(self, body, infos):
        """Send body to geodis WS."""
        ws_url = infos["url"]
        token = infos["token"]
        return requests.post(ws_url, headers={"X-GEODIS-Service": token,}, data=body,)

    def handle_500(self, response):
        """Handle reponse in case of ERROR 500 type."""
        # TODO : put a try catch (like wrong server)
        log.warning("Geodis error 500")
        errors = [{"id": "", "message": "",}]
        raise CarrierError(response, errors)

    def handle_true_negative_error(self, response, payload):
        """When servers answer an error with a 200 status code."""
        errors = [
            {
                "id": payload.get("codeErreur", ""),
                "message": payload.get("texteErreur", ""),
            }
        ]
        raise CarrierError(response, errors)

    def handle_200(self, response):
        """Handle response type 200."""
        payload = json.loads(response.text)
        if payload["ok"] is not True:
            self.handle_true_negative_error(response, payload)
        return {
            "body": payload.get("contenu", []),
            "parts": [],
            "response": response,
        }

    def handle_response(self, response):
        """Handle response of webservice."""
        if response.status_code == 500:
            return self.handle_500(response)
        elif response.status_code == 200:
            return self.handle_200(response)
        else:
            raise CarrierError(
                response,
                [{"id": None, "message": "Unexpected status code from server",}],
            )
