import json
from typing import Dict, Optional

import requests

from federation.hostmeta.parsers import (
    parse_nodeinfo_document, parse_nodeinfo2_document, parse_statisticsjson_document, parse_mastodon_document,
    parse_matrix_document, parse_misskey_document)
from federation.utils.network import fetch_document

HIGHEST_SUPPORTED_NODEINFO_VERSION = 2.1


def fetch_mastodon_document(host):
    doc, status_code, error = fetch_document(host=host, path='/api/v1/instance')
    if not doc:
        return
    try:
        doc = json.loads(doc)
    except json.JSONDecodeError:
        return
    return parse_mastodon_document(doc, host)


def fetch_matrix_document(host: str) -> Optional[Dict]:
    doc, status_code, error = fetch_document(host=host, path='/_matrix/federation/v1/version')
    if not doc:
        return
    try:
        doc = json.loads(doc)
    except json.JSONDecodeError:
        return
    return parse_matrix_document(doc, host)


def fetch_misskey_document(host: str, mastodon_document: Dict=None) -> Optional[Dict]:
    try:
        response = requests.post(f'https://{host}/api/meta')  # ¯\_(ツ)_/¯
    except Exception:
        return
    try:
        doc = response.json()
    except json.JSONDecodeError:
        return
    if response.status_code == 200:
        return parse_misskey_document(doc, host, mastodon_document=mastodon_document)


def fetch_nodeinfo_document(host):
    doc, status_code, error = fetch_document(host=host, path='/.well-known/nodeinfo')
    if not doc:
        return
    try:
        doc = json.loads(doc)
    except json.JSONDecodeError:
        return

    url, highest_version = '', 0.0

    if doc.get('0'):
        # Buggy NodeInfo from certain old Hubzilla versions
        url = doc.get('0', {}).get('href')
    elif isinstance(doc.get('links'), dict):
        # Another buggy NodeInfo from certain old Hubzilla versions
        url = doc.get('links').get('href')
    else:
        for link in doc.get('links'):
            version = float(link.get('rel').split('/')[-1])
            if highest_version < version <= HIGHEST_SUPPORTED_NODEINFO_VERSION:
                url, highest_version = link.get('href'), version

    if not url:
        return

    doc, status_code, error = fetch_document(url=url)
    if not doc:
        return
    try:
        doc = json.loads(doc)
    except json.JSONDecodeError:
        return
    return parse_nodeinfo_document(doc, host)


def fetch_nodeinfo2_document(host):
    doc, status_code, error = fetch_document(host=host, path='/.well-known/x-nodeinfo2')
    if not doc:
        return
    try:
        doc = json.loads(doc)
    except json.JSONDecodeError:
        return
    return parse_nodeinfo2_document(doc, host)


def fetch_statisticsjson_document(host):
    doc, status_code, error = fetch_document(host=host, path='/statistics.json')
    if not doc:
        return
    try:
        doc = json.loads(doc)
    except json.JSONDecodeError:
        return
    return parse_statisticsjson_document(doc, host)

[((15, 30, 15, 80), 'federation.utils.network.fetch_document', 'fetch_document', (), '', False, 'from federation.utils.network import fetch_document\n'), ((22, 11, 22, 45), 'federation.hostmeta.parsers.parse_mastodon_document', 'parse_mastodon_document', ({(22, 35, 22, 38): 'doc', (22, 40, 22, 44): 'host'}, {}), '(doc, host)', False, 'from federation.hostmeta.parsers import parse_nodeinfo_document, parse_nodeinfo2_document, parse_statisticsjson_document, parse_mastodon_document, parse_matrix_document, parse_misskey_document\n'), ((26, 30, 26, 94), 'federation.utils.network.fetch_document', 'fetch_document', (), '', False, 'from federation.utils.network import fetch_document\n'), ((33, 11, 33, 43), 'federation.hostmeta.parsers.parse_matrix_document', 'parse_matrix_document', ({(33, 33, 33, 36): 'doc', (33, 38, 33, 42): 'host'}, {}), '(doc, host)', False, 'from federation.hostmeta.parsers import parse_nodeinfo_document, parse_nodeinfo2_document, parse_statisticsjson_document, parse_mastodon_document, parse_matrix_document, parse_misskey_document\n'), ((50, 30, 50, 85), 'federation.utils.network.fetch_document', 'fetch_document', (), '', False, 'from federation.utils.network import fetch_document\n'), ((75, 30, 75, 53), 'federation.utils.network.fetch_document', 'fetch_document', (), '', False, 'from federation.utils.network import fetch_document\n'), ((82, 11, 82, 45), 'federation.hostmeta.parsers.parse_nodeinfo_document', 'parse_nodeinfo_document', ({(82, 35, 82, 38): 'doc', (82, 40, 82, 44): 'host'}, {}), '(doc, host)', False, 'from federation.hostmeta.parsers import parse_nodeinfo_document, parse_nodeinfo2_document, parse_statisticsjson_document, parse_mastodon_document, parse_matrix_document, parse_misskey_document\n'), ((86, 30, 86, 88), 'federation.utils.network.fetch_document', 'fetch_document', (), '', False, 'from federation.utils.network import fetch_document\n'), ((93, 11, 93, 46), 'federation.hostmeta.parsers.parse_nodeinfo2_document', 'parse_nodeinfo2_document', ({(93, 36, 93, 39): 'doc', (93, 41, 93, 45): 'host'}, {}), '(doc, host)', False, 'from federation.hostmeta.parsers import parse_nodeinfo_document, parse_nodeinfo2_document, parse_statisticsjson_document, parse_mastodon_document, parse_matrix_document, parse_misskey_document\n'), ((97, 30, 97, 80), 'federation.utils.network.fetch_document', 'fetch_document', (), '', False, 'from federation.utils.network import fetch_document\n'), ((104, 11, 104, 51), 'federation.hostmeta.parsers.parse_statisticsjson_document', 'parse_statisticsjson_document', ({(104, 41, 104, 44): 'doc', (104, 46, 104, 50): 'host'}, {}), '(doc, host)', False, 'from federation.hostmeta.parsers import parse_nodeinfo_document, parse_nodeinfo2_document, parse_statisticsjson_document, parse_mastodon_document, parse_matrix_document, parse_misskey_document\n'), ((19, 14, 19, 29), 'json.loads', 'json.loads', ({(19, 25, 19, 28): 'doc'}, {}), '(doc)', False, 'import json\n'), ((30, 14, 30, 29), 'json.loads', 'json.loads', ({(30, 25, 30, 28): 'doc'}, {}), '(doc)', False, 'import json\n'), ((38, 19, 38, 60), 'requests.post', 'requests.post', ({(38, 33, 38, 59): 'f"""https://{host}/api/meta"""'}, {}), "(f'https://{host}/api/meta')", False, 'import requests\n'), ((46, 15, 46, 85), 'federation.hostmeta.parsers.parse_misskey_document', 'parse_misskey_document', (), '', False, 'from federation.hostmeta.parsers import parse_nodeinfo_document, parse_nodeinfo2_document, parse_statisticsjson_document, parse_mastodon_document, parse_matrix_document, parse_misskey_document\n'), ((54, 14, 54, 29), 'json.loads', 'json.loads', ({(54, 25, 54, 28): 'doc'}, {}), '(doc)', False, 'import json\n'), ((79, 14, 79, 29), 'json.loads', 'json.loads', ({(79, 25, 79, 28): 'doc'}, {}), '(doc)', False, 'import json\n'), ((90, 14, 90, 29), 'json.loads', 'json.loads', ({(90, 25, 90, 28): 'doc'}, {}), '(doc)', False, 'import json\n'), ((101, 14, 101, 29), 'json.loads', 'json.loads', ({(101, 25, 101, 28): 'doc'}, {}), '(doc)', False, 'import json\n')]