#!/usr/bin/env python3
import html
import json
import sys

import pywikiapi
import mwparserfromhell
import requests

OSMWIKI_ENDPOINT = 'https://wiki.openstreetmap.org/w/api.php'

osmwiki = pywikiapi.Site(OSMWIKI_ENDPOINT)

# https://wiki.openstreetmap.org/w/index.php?title=Template:Proposal_page&action=edit

res = requests.get(
    'https://wiki.openstreetmap.org/w/api.php?action=expandtemplates&prop=wikitext&format=json&text={%7B%23invoke:languages/table%7Cjson}}'
)
langs = json.loads(res.json()['expandtemplates']['wikitext'])


def get_template_val(tpl, name):
    param = tpl.get(name, None)
    if param:
        value = param.value.strip()
        if value:
            # turn empty strings into None
            return value


proposals = []


def eprint(*args):
    print(*args, file=sys.stderr)


def is_stub(doc):
    if any(
        doc.ifilter_templates(matches=lambda t: t.name.matches('Archived proposal'))
    ):
        return False

    if not any(doc.ifilter_headings()):
        # detect proposals without headings as stubs
        return True

    if not any(
        n
        for n in doc.nodes
        # any text
        if isinstance(n, mwparserfromhell.nodes.text.Text)
        # other than newlines
        and n.strip()
        # and "Please comment on the [[{{TALKPAGENAME}}|discussion page]]."
        and n.strip() not in ('Please comment on the', '.')
    ):
        # detect proposals without text as stubs
        return True

    return False


for page in osmwiki.query_pages(
    generator='embeddedin',
    geititle='Template:Proposal Page',
    geilimit='max',
    prop='revisions',
    rvprop='content',
    rvslots='main',
):
    page_title = page['title']
    text = page['revisions'][0]['slots']['main']['content']
    doc = mwparserfromhell.parse(text)
    proposal_page_templates = doc.filter_templates(
        matches=lambda t: t.name.matches('Proposal Page')
    )

    if not proposal_page_templates:
        eprint('{{Proposal Page}} not found in', page_title)
        continue

    for comment in doc.ifilter_comments():
        # remove comments like <!-- Date the RFC email is sent to the Tagging list: YYYY-MM-DD -->
        doc.remove(comment)

    tpl = proposal_page_templates[0]

    status = get_template_val(tpl, 'status')
    if status:
        status = status.lower()

    if is_stub(doc):
        if status in ('approved', 'rejected'):
            eprint(f'WARNING {status} proposal is a stub', page['title'])
        else:
            eprint('skipping stub', page['title'])
            continue

    name = get_template_val(tpl, 'name')
    if name:
        name = html.unescape(name)

    draft_start = get_template_val(tpl, 'draftStartDate')
    if draft_start in ('*', '-'):
        draft_start = None

    rfc_start = get_template_val(tpl, 'rfcStartDate')
    if rfc_start in ('*', '-'):
        rfc_start = None

    vote_start = get_template_val(tpl, 'voteStartDate')
    if vote_start in ('*', '-'):
        vote_start = None

    definition = get_template_val(tpl, 'definition')
    users = get_template_val(tpl, 'users') or get_template_val(tpl, 'user')

    parts = page_title.split(':', maxsplit=1)
    parts[0] = parts[0].lower()

    lang = None
    if parts[0] in langs:
        lang = parts[0]

    proposals.append(
        dict(
            page_title=page_title,
            lang=lang,
            name=name,
            status=status,
            definition=definition,
            draft_start=draft_start,
            rfc_start=rfc_start,
            vote_start=vote_start,
            authors=users,
        )
    )

STATUSES = {
    'voting': 0,
    'post-vote': 1,
    'proposed': 2,
    'draft': 3,
    'approved': 4,
    'inactive': 5,
    'rejected': 6,
    'abandoned': 7,
    'canceled': 8,
    'obsoleted': 9,
}


def sort_key(proposal):
    status = proposal['status']

    if status in ('voting', 'approved', 'rejected'):
        date = proposal['vote_start'] or ''
    elif status == 'proposed':
        date = proposal['rfc_start'] or ''
    else:
        date = proposal['draft_start'] or ''

    return (-STATUSES.get(proposal['status'], 10), date)


proposals.sort(key=sort_key, reverse=True)

json.dump(
    [{k: v for k, v in p.items() if v is not None} for p in proposals], sys.stdout
)