"""Functions for detecting and patrolling RfD'd pages.

When a redirect is nominated for discussion at RfD, it is placed in the
articles queue of Special:NewPagesFeed.  These functions identify such
"articles", double-check that they've been filed to RfD, and, if so,
patrol them.  After 30 minutes of not being filed to RfD, a page is
logged as such on-wiki.
"""
import datetime as dt
from enum import Enum
import re

import mwparserfromhell as mwph
from pywikibot import Page

import api
import utils
from utils import Namespace, OnWikiLogger, Title, ZBError

# This is only guaranteed to match the output of {{subst:rfd}}.  If for
# some reason someone manually added the subst'd output and changed with
# the spacing, it would not read as a match.  This can be changed if
# there's anyone out there actually doing that.
#
# Note that this does not check wikilink validity, since an invalidly-
# formulated link could still potentially land at RfD (although it would
# probably be speedily resolved).
# pylint: disable=line-too-long
_TAGGED = re.compile(
    r"""\{\{<includeonly>safesubst:</includeonly>\#invoke:RfD(\|.*?){3}month = \w+
\|day = [ \d]\d
\|year = \d{4}
\|time = \d{2}:\d{2}
\|timestamp = \d{14}
<!-- The above content is generated by \{\{subst:rfd\}\}\. -->
<!-- End of RFD message\. Don't edit anything above here, but feel free to edit below here\. -->\|content=
\#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt] *\[\[.+?\]\]"""
)
_onwiki_logger = OnWikiLogger("skippedRfDs.json")


class _Messages(Enum):
    RFD0 = "[[{page}]] not filed to [[{rfd}]] (currently a redlink)."
    RFD1 = "[[{page}]] not filed to [[{rfd}]]."
    RFD2 = ("[[{page}]] filed to [[{rfd}]], but that log page has "
            "not been transcluded to main RfD page.")


def check_rfd(page: Page) -> bool:
    """Check if a page is subject to an ongoing RfD.

    First checks for the {{subst:rfd}} tag, then for whether there's an
    entry at the corresponding RfD log page.

    Arg:
      page:  A Page corresponding to a wikipage to be checked.

    Returns:
      A bool, True if both TAGGED matches and checkfiled() returns True.
      (If the former but not the latter, the distinction is made clear
      by logs.)
    """
    return bool(_TAGGED.match(page.text)) and _check_filed(page)


def _check_filed(page: Page) -> bool:
    """Check an RfD log page for an anchor matching the page's title.

    {{subst:rfd2}} makes such anchors automatically.  As with TAGGED, no
    guarantee of matching markup that renders the same way but is
    generated through some other means.

    Arg:
      page:  A Page corresponding to a wikipage tagged with
        {{subst:rfd}}.

    Returns:
      A bool indicating whether an RfD entry exists matching the page's
      title.
    """
    now = api.site_time()
    rfd_title = _extract_rfd(page)
    page_title = Title.from_page(page)
    try:
        rfd = api.get_page(title=rfd_title.pagename,
                           ns=rfd_title.namespace,
                           must_exist=True)
    except ZBError:
        print(f"No RfD page for {page_title}.")
        utils.log_local(page_title, "no_rfd_logpage.txt")
        _onwiki_logger.log(_Messages.RFD0, page_title, now, rfd=rfd_title)
        return False

    # What idiot made this line necessary by building quotation-mark escaping
    # into {{rfd2}}?  Oh right.  Me.
    anchor = page_title.replace('"', "&quot;").removeprefix(":")
    filed = f'*<span id="{anchor}">' in rfd.text
    if not filed:
        print(f"RfD not filed for {page_title}.")
        utils.log_local(page_title, "rfd_not_filed.txt")
        if now - page.editTime() > dt.timedelta(minutes=30):
            _onwiki_logger.log(_Messages.RFD1, page_title, now,
                               rfd=rfd_title)
    elif ("Wikipedia:Redirects for discussion"
          not in [i.title() for i in rfd.embeddedin()]):
        print(f"{rfd_title} not transcluded to main RfD page.")
        utils.log_local(page_title, "rfd_log_not_transcluded.txt")
        _onwiki_logger.log(_Messages.RFD2, page_title, now, rfd=rfd_title)
        return False
    return filed


def _extract_rfd(page: Page) -> Title:
    """Get the title of the log page referenced by an RfD tag.

    Uses the standard RfD log format and the `year`, `month`, and `day`
    parameters in {{subst:rfd}}.  This accounts for RfDs filed to
    previous dates.

    Arg:
      page:  A Page corresponding to a wikipage tagged with
        {{subst:rfd}}.

    Returns:
      A Title for an RfD log page, without guarantee that the page exists.
    """
    # Ugly hack around <https://github.com/earwig/mwparserfromhell/issues/251>.
    text = page.text.replace("<includeonly>safesubst:</includeonly>", "")
    parsed = mwph.parse(text)
    template = parsed.filter_templates()[0]
    year, month, day = (template.get(s).value.strip()
                        for s in ("year", "month", "day"))
    return Title(Namespace.PROJECT,
                 f"Redirects for discussion/Log/{year} {month} {day}")


def cleanup() -> None:
    """Public wrapper for `_onwiki_logger.cleanup()`."""
    if _onwiki_logger.cleanup():
        print("Cleaning up RfD log on-wiki")
