import json
import os
import re
import time
from urllib.request import urlopen

import requests

from odoo.exceptions import ValidationError

from odoo.addons.eurooffice_odoo.utils import jwt_utils


def valid_url(url):
    if not url:
        return True
    # pylint: disable=anomalous-backslash-in-string
    pattern = "^(https?:\/\/)?[\w-]{1,32}(\.[\w-]{1,32})*[\/\w-]*(:[\d]{1,5}\/?)?$"
    # pylint: enable=anomalous-backslash-in-string
    if re.findall(pattern, url):
        return True
    return False


def settings_validation(self):
    base_url = self.doc_server_odoo_url
    public_url = self.doc_server_public_url
    inner_url = self.doc_server_inner_url
    jwt_secret = self.doc_server_jwt_secret
    jwt_header = self.doc_server_jwt_header
    disable_certificate = self.doc_server_disable_certificate
    demo = self.doc_server_demo

    url = public_url
    if inner_url and inner_url != public_url:
        url = inner_url

    check_mixed_content(base_url, url, demo)
    check_doc_serv_url(url, demo, disable_certificate)
    check_doc_serv_command_service(self.env, url, jwt_secret, jwt_header, disable_certificate, demo)
    check_doc_serv_convert_service(self.env, url, base_url, jwt_secret, jwt_header, disable_certificate, demo)


def check_mixed_content(base_url, url, demo):
    if base_url.startswith("https") and not url.startswith("https"):
        get_message_error("Mixed Active Content is not allowed. HTTPS address for Document Server is required.", demo)


def check_doc_serv_url(url, demo, disable_certificate):
    try:
        url = os.path.join(url, "healthcheck")

        context = None
        if disable_certificate and url.startswith("https://"):
            import ssl

            context = ssl._create_unverified_context()

        response = urlopen(url, timeout=30, context=context)

        healthcheck = response.read()

        if not healthcheck:
            get_message_error(os.path.join(url, "healthcheck") + " returned false.", demo)

    except ValidationError as e:
        get_message_error(str(e), demo)
    except Exception:
        get_message_error("Euro-Office cannot be reached", demo)


def check_doc_serv_command_service(env, url, jwt_secret, jwt_header, disable_certificate, demo):
    try:
        headers = {"Content-Type": "application/json"}
        body_json = {"c": "version"}

        if jwt_secret is not None and jwt_secret is not False and jwt_secret != "":
            payload = {"payload": body_json}

            header_token = jwt_utils.encode_payload(env, payload, jwt_secret)
            headers[jwt_header] = "Bearer " + header_token

            token = jwt_utils.encode_payload(env, body_json, jwt_secret)
            body_json["token"] = token

        response = requests.post(
            os.path.join(url, "coauthoring/CommandService.ashx"),
            verify=not disable_certificate,
            timeout=60,
            data=json.dumps(body_json),
            headers=headers,
        )

        if response.json()["error"] == 6:
            get_message_error("Authorization error", demo)

        if response.json()["error"] != 0:
            get_message_error(
                os.path.join(url, "coauthoring/CommandService.ashx")
                + " returned error: "
                + str(response.json()["error"]),
                demo,
            )

    except ValidationError as e:
        get_message_error(str(e), demo)
    except Exception:
        get_message_error("Error when trying to check CommandService", demo)


def check_doc_serv_convert_service(env, url, base_url, jwt_secret, jwt_header, disable_certificate, demo):
    file_url = os.path.join(base_url, "eurooffice/file/content/test.txt")

    result = convert(env, file_url, url, jwt_secret, jwt_header, disable_certificate)

    if isinstance(result, str):
        return get_message_error(result, demo)


def convert(env, file_url, url, jwt_secret, jwt_header, disable_certificate):
    body_json = {
        "key": int(time.time()),
        "url": file_url,
        "filetype": "txt",
        "outputtype": "txt",
    }

    headers = {
        "Content-Type": "application/json",
        "Accept": "application/json",
    }

    if bool(jwt_secret):
        payload = {"payload": body_json}
        header_token = jwt_utils.encode_payload(env, payload, jwt_secret)
        headers[jwt_header] = "Bearer " + header_token
        token = jwt_utils.encode_payload(env, body_json, jwt_secret)
        body_json["token"] = token

    try:
        response = requests.post(
            os.path.join(url, "ConvertService.ashx"),
            verify=not disable_certificate,
            timeout=60,
            data=json.dumps(body_json),
            headers=headers,
        )

        if response.status_code == 200:
            response_json = response.json()
            if "error" in response_json:
                return get_conversion_error_message(response_json.get("error"))
        else:
            return f"Document conversion service returned status {response.status_code}"

    except Exception:
        return "Document conversion service cannot be reached"


def get_message_error(message, demo):
    if demo:
        raise ValidationError(f"Error connecting to demo server: {message}")
    else:
        raise ValidationError(message)


def get_conversion_error_message(errorCode):
    errorDictionary = {
        -1: "Unknown error",
        -2: "Conversion timeout error",
        -3: "Conversion error",
        -4: "Error while downloading the document file to be converted",
        -5: "Incorrect password",
        -6: "Error while accessing the conversion result database",
        -7: "Input error",
        -8: "Invalid token",
    }

    try:
        return errorDictionary[errorCode]

    except Exception:
        return "Undefined error code"
