import json
import uuid

import requests

from django.conf import settings


class TranslationException(Exception):
    pass


def translate(text, from_language, to_language):
    AZURE_CLIENT_SECRET = getattr(settings, "AZURE_CLIENT_SECRET", None)
    GOOGLE_APPLICATION_CREDENTIALS_PATH = getattr(
        settings, "GOOGLE_APPLICATION_CREDENTIALS_PATH", None
    )
    GOOGLE_PROJECT_ID = getattr(settings, "GOOGLE_PROJECT_ID", None)
    DEEPL_AUTH_KEY = getattr(settings, "DEEPL_AUTH_KEY", None)

    if DEEPL_AUTH_KEY:
        deepl_language_code = None
        DEEPL_LANGUAGES = getattr(settings, "DEEPL_LANGUAGES", None)
        if type(DEEPL_LANGUAGES) is dict:
            deepl_language_code = DEEPL_LANGUAGES.get(to_language, None)

        if deepl_language_code is None:
            deepl_language_code = to_language[:2].upper()

        return translate_by_deepl(
            text,
            deepl_language_code.upper(),
            DEEPL_AUTH_KEY,
        )

    elif AZURE_CLIENT_SECRET:
        return translate_by_azure(text, from_language, to_language, AZURE_CLIENT_SECRET)
    elif GOOGLE_APPLICATION_CREDENTIALS_PATH and GOOGLE_PROJECT_ID:
        return translate_by_google(
            text,
            from_language,
            to_language,
            GOOGLE_APPLICATION_CREDENTIALS_PATH,
            GOOGLE_PROJECT_ID,
        )
    else:
        raise TranslationException("No translation API service is configured.")


def translate_by_deepl(text, to_language, auth_key):
    if auth_key.lower().endswith(":fx"):
        endpoint = "https://api-free.deepl.com"
    else:
        endpoint = "https://api.deepl.com"

    r = requests.post(
        f"{endpoint}/v2/translate",
        headers={"Authorization": f"DeepL-Auth-Key {auth_key}"},
        data={
            "target_lang": to_language.upper(),
            "text": text,
        },
    )
    return r.json().get("translations")[0].get("text")


def translate_by_azure(text, from_language, to_language, subscription_key):
    """
    This method does the heavy lifting of connecting to the translator API and fetching a response
    :param text: The source text to be translated
    :param from_language: The language of the source text
    :param to_language: The target language to translate the text into
    :param subscription_key: An API key that grants you access to the Azure translation service
    :return: Returns the response from the AZURE service as a python object. For more information about the
    response, please visit
    https://docs.microsoft.com/en-us/azure/cognitive-services/translator/reference/v3-0-translate?tabs=curl
    """

    AZURE_TRANSLATOR_HOST = "https://api.cognitive.microsofttranslator.com"
    AZURE_TRANSLATOR_PATH = "/translate?api-version=3.0"

    headers = {
        "Ocp-Apim-Subscription-Key": subscription_key,
        "Content-type": "application/json",
        "X-ClientTraceId": str(uuid.uuid4()),
    }

    url_parameters = {"from": from_language, "to": to_language}

    request_data = [{"text": text}]

    api_hostname = AZURE_TRANSLATOR_HOST + AZURE_TRANSLATOR_PATH
    r = requests.post(
        api_hostname,
        headers=headers,
        params=url_parameters,
        data=json.dumps(request_data),
    )
    api_response = json.loads(r.text)

    try:
        # result will be a dict if there is an error, e.g.
        # {
        #   "success": false,
        #    "error": "Microsoft Translation API error: Error code 401000,
        #             The request is not authorized because credentials are missing or invalid."
        # }
        if isinstance(api_response, dict):
            api_error = api_response.get("error")
            error_code = api_error.get("code")
            error_message = api_error.get("message")

            raise TranslationException(
                "Microsoft Translation API error: Error code {}, {}".format(
                    error_code, error_message
                )
            )
        else:
            # response body will be of the form:
            # [
            #     {
            #         "translations":[
            #             {"text": "some chinese text that gave a build error on travis ci", "to": "zh-Hans"}
            #         ]
            #     }
            # ]
            # for more information, please visit
            # https://docs.microsoft.com/en-us/azure/cognitive-services/translator/reference/v3-0-translate?tabs=curl

            translations = api_response[0].get("translations")
            translated_text = translations[0].get("text")

            return translated_text
    except requests.exceptions.RequestException as err:
        raise TranslationException(
            "Error connecting to Microsoft Translation Service: {0}".format(err)
        )


def translate_by_google(
    text, input_language, output_language, creadentials_path, project_id
):
    from google.cloud import translate as google_translate

    client = google_translate.TranslationServiceClient.from_service_account_json(
        creadentials_path
    )
    parent = "projects/{}/locations/{}".format(project_id, "global")
    try:
        api_response = client.translate_text(
            request=dict(
                parent=parent,
                contents=[text],
                mime_type="text/plain",
                source_language_code=input_language,
                target_language_code=output_language.split(".", 1)[0],
            )
        )
    except Exception as e:
        raise TranslationException("Google API error: {}".format(e))
    else:
        return str(api_response.translations[0].translated_text)
