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)

[((429, 479), 'federation.utils.network.fetch_document', 'fetch_document', ([], {'host': 'host', 'path': '"""/api/v1/instance"""'}), "(host=host, path='/api/v1/instance')\n", (443, 479), False, 'from federation.utils.network import fetch_document\n'), ((609, 643), 'federation.hostmeta.parsers.parse_mastodon_document', 'parse_mastodon_document', (['doc', 'host'], {}), '(doc, host)\n', (632, 643), 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'), ((732, 796), 'federation.utils.network.fetch_document', 'fetch_document', ([], {'host': 'host', 'path': '"""/_matrix/federation/v1/version"""'}), "(host=host, path='/_matrix/federation/v1/version')\n", (746, 796), False, 'from federation.utils.network import fetch_document\n'), ((926, 958), 'federation.hostmeta.parsers.parse_matrix_document', 'parse_matrix_document', (['doc', 'host'], {}), '(doc, host)\n', (947, 958), 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'), ((1444, 1499), 'federation.utils.network.fetch_document', 'fetch_document', ([], {'host': 'host', 'path': '"""/.well-known/nodeinfo"""'}), "(host=host, path='/.well-known/nodeinfo')\n", (1458, 1499), False, 'from federation.utils.network import fetch_document\n'), ((2251, 2274), 'federation.utils.network.fetch_document', 'fetch_document', ([], {'url': 'url'}), '(url=url)\n', (2265, 2274), False, 'from federation.utils.network import fetch_document\n'), ((2404, 2438), 'federation.hostmeta.parsers.parse_nodeinfo_document', 'parse_nodeinfo_document', (['doc', 'host'], {}), '(doc, host)\n', (2427, 2438), 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'), ((2507, 2565), 'federation.utils.network.fetch_document', 'fetch_document', ([], {'host': 'host', 'path': '"""/.well-known/x-nodeinfo2"""'}), "(host=host, path='/.well-known/x-nodeinfo2')\n", (2521, 2565), False, 'from federation.utils.network import fetch_document\n'), ((2695, 2730), 'federation.hostmeta.parsers.parse_nodeinfo2_document', 'parse_nodeinfo2_document', (['doc', 'host'], {}), '(doc, host)\n', (2719, 2730), 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'), ((2804, 2854), 'federation.utils.network.fetch_document', 'fetch_document', ([], {'host': 'host', 'path': '"""/statistics.json"""'}), "(host=host, path='/statistics.json')\n", (2818, 2854), False, 'from federation.utils.network import fetch_document\n'), ((2984, 3024), 'federation.hostmeta.parsers.parse_statisticsjson_document', 'parse_statisticsjson_document', (['doc', 'host'], {}), '(doc, host)\n', (3013, 3024), 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'), ((534, 549), 'json.loads', 'json.loads', (['doc'], {}), '(doc)\n', (544, 549), False, 'import json\n'), ((851, 866), 'json.loads', 'json.loads', (['doc'], {}), '(doc)\n', (861, 866), False, 'import json\n'), ((1076, 1117), 'requests.post', 'requests.post', (['f"""https://{host}/api/meta"""'], {}), "(f'https://{host}/api/meta')\n", (1089, 1117), False, 'import requests\n'), ((1306, 1376), 'federation.hostmeta.parsers.parse_misskey_document', 'parse_misskey_document', (['doc', 'host'], {'mastodon_document': 'mastodon_document'}), '(doc, host, mastodon_document=mastodon_document)\n', (1328, 1376), 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'), ((1554, 1569), 'json.loads', 'json.loads', (['doc'], {}), '(doc)\n', (1564, 1569), False, 'import json\n'), ((2329, 2344), 'json.loads', 'json.loads', (['doc'], {}), '(doc)\n', (2339, 2344), False, 'import json\n'), ((2620, 2635), 'json.loads', 'json.loads', (['doc'], {}), '(doc)\n', (2630, 2635), False, 'import json\n'), ((2909, 2924), 'json.loads', 'json.loads', (['doc'], {}), '(doc)\n', (2919, 2924), False, 'import json\n')]