from . import command
import requests
import string
import html
import logging
import re
import iso639
import mwparserfromhell
from collections import deque
from dataclasses import dataclass

logger = logging.getLogger("wiktionary")

language_mapping = {'nld': 'Nederlands'}

@dataclass
class Text:
    text: str

@dataclass
class Template:
    text: str

def expand_template(pagename, wikitext):
    template_params = {'action': 'expandtemplates', 'title': pagename, 'text': wikitext, 'prop': 'wikitext', 'format': 'json'}
    api_base = "https://nl.wiktionary.org/w/api.php"

    resp = requests.get(api_base, params=template_params)
    if resp.status_code != 200:
        logger.warning(f"Wiktionary lookup: status code {resp.status_code}")

    data = resp.json()
    return data["expandtemplates"]["wikitext"]


@command('(wiktionary|wi|winl) ([^ ]+)', pass_groups=True, inline=True)
def wiktionary(bea, bot, update, groups):
    cmd = groups[0]
    nl_only = (cmd == 'winl')
    word = groups[1]
    params = {"action": "parse", "page": word, "prop": "wikitext", "formatversion": 2, "format": "json"}
    api_base = "https://nl.wiktionary.org/w/api.php"

    try:
        resp = requests.get(api_base, params=params)
        if resp.status_code != 200:
            logger.warning(f"Wiktionary lookup: status code {resp.status_code}")
    except requests.ConnectionError:
        return bea.reply("Ik kon Wiktionary niet bereiken, sorry.")

    try:
        data = resp.json()
        wikitext = data["parse"]["wikitext"]
    except KeyError:
        return bea.reply("Dat woord kon ik niet vinden in het (Nederlandse) wikiwoordenboek.")

    result = ""

    components = deque(mwparserfromhell.parse(wikitext, skip_style_tags=True).nodes)
    entry = ""
    in_list = False
    saw_nl = False
    while components:
        component = components.popleft()
        logger.info(f"Handling component: {component} (in list: {in_list})")
        if isinstance(component, mwparserfromhell.nodes.Tag):
            if component.startswith('#'):
                in_list = True
            elif component.tag == 'span':
                components.extendleft(reversed(component.contents.nodes))

        if isinstance(component, mwparserfromhell.nodes.Template):
            language_template = re.match("{{=(.+)=}}", str(component))
            if language_template:
                lang_code = language_template.group(1)
                try:
                    lang = language_mapping.get(lang_code) or iso639.languages.get(part3=lang_code).name
                except KeyError:
                    lang = lang_code.title()
                if (lang == 'Nederlands'):
                    saw_nl = True
                if (lang != 'Nederlands' and (nl_only and not saw_nl)):
                    continue
                if (lang != 'Nederlands' and (nl_only and saw_nl)):
                    break
                result += '\n<b>' + lang + '</b>\n'
            if not in_list: continue
            expanded = expand_template(word, str(component))
            components.extendleft(reversed(mwparserfromhell.parse(expanded, skip_style_tags=True).nodes))
            continue

        if not in_list or (nl_only and not saw_nl):
            continue

        if in_list and isinstance(component, mwparserfromhell.nodes.Text):
            entry += html.escape(str(component))
        if in_list and isinstance(component, mwparserfromhell.nodes.Wikilink):
            if component.title.startswith('#'):
                entry += f'<i>zie: {html.escape(str(component.title)[1:])}</i>'
            else:
                if component.text:
                    entry += f'<i>{html.escape(str(component.text))}</i>'
                elif component.title and not any(c in string.punctuation for c in str(component.title)):
                    entry += f'<i>{html.escape(str(component.title))}</i>'
        if entry.endswith('\n'):
            result += "• " + entry
            entry = ""
            in_list = False

    if entry:
        result += "• " + entry

    logger.warning("Going to send: " + result)

    if not result:
        result = "Geen resultaat"

    if update.inline_query is not None:
        bea.inline_reply_text("Resultaat", result, parse_mode='HTML')
    else:
        bea.reply(result, parse_mode='HTML')

def init(bea, _config):
    return [wiktionary]

