import time
from json import JSONDecodeError
from typing import Any, Dict, Optional
from urllib.parse import urljoin

import requests

from aleksis.core.util.core_helpers import get_site_preferences


class MatrixException(Exception):
    pass


def build_url(path):
    return urljoin(
        urljoin(get_site_preferences()["matrix__homeserver"], "_matrix/client/v3/"), path
    )


def get_headers():
    return {
        "Authorization": "Bearer " + get_site_preferences()["matrix__access_token"],
    }


def do_matrix_request(method: str, url: str, body: Optional[dict] = None) -> Dict[str, Any]:
    """Do a HTTP request to the Matrix Client Server API."""
    while True:
        res = requests.request(method=method, url=build_url(url), headers=get_headers(), json=body)
        if res.status_code != requests.codes.ok:
            try:
                data = res.json()
            except JSONDecodeError:
                raise MatrixException(res.text)

            # If rate limit exceeded, wait and retry
            if data.get("errcode", "") == "M_LIMIT_EXCEEDED":
                time.sleep(data["retry_after_ms"] / 1000)
            else:
                raise MatrixException(data)
        else:
            break

    return res.json()