"""
Sphinx extension to generate a table from a DOAP file in XML format.

This is a helper to generate "features" pages for the docs of slidge-powered
gateways.
"""

import xml.etree.ElementTree as ET
from pathlib import Path

import requests
from docutils import nodes
from sphinx.util.docutils import SphinxDirective
from sphinx.util.logging import getLogger

from . import __version__


def parse(el):
    status = el.find("{https://linkmauve.fr/ns/xmpp-doap#}status").text
    url = el.find("{https://linkmauve.fr/ns/xmpp-doap#}xep").get(
        "{http://www.w3.org/1999/02/22-rdf-syntax-ns#}resource"
    )

    note_elem = el.find("{https://linkmauve.fr/ns/xmpp-doap#}note")

    if note_elem is not None:
        note = note_elem.text
    else:
        note = ""

    if not note:
        note = DEFAULT_NOTE.get(status, status)

    return url, status, note


def get_xep_titles(xep_urls: list[str]):
    params = {
        "sql": "select title, url from xeps where "
        + " or ".join(f'"url" = :p{i}' for i in range(len(xep_urls)))
    }
    for i, url in enumerate(xep_urls):
        params[f"p{i}"] = url
    log.debug("Request params: %s", params)
    resp = requests.get(
        "https://data.xmpp.net/explore/xmpp.json", params=params, timeout=5
    )
    resp.raise_for_status()
    json = resp.json()
    if not json["ok"]:
        raise RuntimeError("data.xmpp.net returned an error: %s", json)
    titles = {}
    for row in json["rows"]:
        titles[row[1]] = row[0]
    return [titles[x] for x in xep_urls]


class Doap(SphinxDirective):
    has_content = True

    def run(self):
        xml = ET.parse(Path(self.get_location()).parent / self.content[0])

        table = nodes.table()
        tgroup = nodes.tgroup()

        colspec = nodes.colspec()

        tgroup += colspec
        tgroup += colspec
        tgroup += colspec

        table += tgroup

        tbody = nodes.tbody()

        xep_urls = []
        statuses = []
        notes = []

        for el in xml.iter("{https://linkmauve.fr/ns/xmpp-doap#}SupportedXep"):
            try:
                url, status, note = parse(el)
            except Exception as e:
                log.error("Problem parsing %s", el, exc_info=e)
                continue
            xep_urls.append(url)
            statuses.append(status)
            notes.append(note)

        xep_titles = get_xep_titles(xep_urls)
        for url, status, note, title in zip(xep_urls, statuses, notes, xep_titles):
            row = nodes.row()

            entry = nodes.entry()
            entry.append(nodes.Text(SUPPORT[status]))
            row += entry

            entry = nodes.entry()
            outer = nodes.paragraph("")
            ref = nodes.reference()
            ref["refuri"] = url
            ref.append(nodes.Text(title))
            outer.append(ref)

            entry.append(outer)
            row += entry

            entry = nodes.entry()
            entry.append(nodes.Text(note))
            row += entry

            tbody += row

        tgroup += tbody

        return [table]


def setup(app):
    app.add_directive("doap", Doap)

    return {
        "version": __version__,
        "parallel_read_safe": True,
        "parallel_write_safe": True,
    }


SUPPORT = {"complete": "✅", "wontfix": "❌", "planned": "🔮", "partial": "🤏"}
DEFAULT_NOTE = {
    "complete": "Supported",
    "wontfix": "Unsupported",
    "planned": "Planned",
    "partial": "Partially supported",
}

log = getLogger("doap")
