import hashlib
import json
import logging
from base64 import b64decode

import requests
from django.conf import settings
from django.core.cache import caches

from judge.utils.file_cache import HashFileCache
from judge.utils.unicode import utf8bytes

logger = logging.getLogger("judge.texoid")

TEXOID_ENABLED = hasattr(settings, "TEXOID_URL")


class TexoidRenderer(object):
    def __init__(self):
        self.cache = HashFileCache(
            settings.TEXOID_CACHE_ROOT, settings.TEXOID_CACHE_URL, settings.TEXOID_GZIP
        )
        self.meta_cache = caches[settings.TEXOID_META_CACHE]
        self.meta_cache_ttl = settings.TEXOID_META_CACHE_TTL

    def query_texoid(self, document, hash):
        self.cache.create(hash)

        try:
            response = requests.post(
                settings.TEXOID_URL,
                data=utf8bytes(document),
                headers={
                    "Content-Type": "application/x-tex",
                },
            )
            response.raise_for_status()
        except requests.HTTPError as e:
            if e.response.status == 400:
                logger.error(
                    "Texoid failed to render: %s\n%s", document, e.response.text
                )
            else:
                logger.exception("Failed to connect to texoid for: %s", document)
            return
        except Exception:
            logger.exception("Failed to connect to texoid for: %s", document)
            return

        try:
            data = response.json()
        except ValueError:
            logger.exception(
                "Invalid texoid response for: %s\n%s", document, response.text
            )
            return

        if not data["success"]:
            logger.error("Texoid failure for: %s\n%s", document, data)
            return {"error": data["error"]}

        meta = data["meta"]
        self.cache.cache_data(
            hash, "meta", utf8bytes(json.dumps(meta)), url=False, gzip=False
        )

        result = {
            "png": self.cache.cache_data(hash, "png", b64decode(data["png"])),
            "svg": self.cache.cache_data(hash, "svg", data["svg"].encode("utf-8")),
            "meta": meta,
        }
        return result

    def query_cache(self, hash):
        result = {
            "svg": self.cache.get_url(hash, "svg"),
            "png": self.cache.get_url(hash, "png"),
        }

        key = "texoid:meta:" + hash
        cached_meta = self.meta_cache.get(key)
        if cached_meta is None:
            cached_meta = json.loads(self.cache.read_data(hash, "meta").decode("utf-8"))
            self.meta_cache.set(key, cached_meta, self.meta_cache_ttl)
        result["meta"] = cached_meta

        return result

    def get_result(self, formula):
        hash = hashlib.sha1(utf8bytes(formula)).hexdigest()

        if self.cache.has_file(hash, "svg"):
            return self.query_cache(hash)
        else:
            return self.query_texoid(formula, hash)