# Encoding: UTF-8
"""Rewrite Markdown strings to use identifiers instead of names

This is an unmaintained one-shot script, only included in the repo for reference.

"""

from functools import partial
import sys
import re

from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.sql.expression import func

from pokedex.db import connect, tables

sanity_re = re.compile(ur"^[-A-Za-z0-9 é\[\]{}.%':;,×/()\"|–`—!*♂♀\\]$")

# RE that matches anything that might look like a link
fuzzy_link_re = re.compile(r"""
    \[
        [^]]+
    \]
    \{
        [^}]+
    \}""", re.VERBOSE)

# Very specific RE that matches links that appear in our Markdown strings
strict_link_re = re.compile(r"""
            \[
                (?P<label>
                    [-A-Za-z 0-9'.]{,30}
                )
            \]
            \{
                (?P<category>
                    [a-z]{,20}
                )
                (
                    :
                    (?P<target>
                        [A-Za-z 0-9]{,20}
                    )
                )?
            \}
        """, re.VERBOSE)

english_id = 9

def is_md_col(column):
    return column.info.get('format') == 'markdown'

manual_replacements = {
    (
        u'Used in battle\n:   Attempts to [catch]{mechanic} a wild Pok\xe9mon, using a catch rate of 1.5\xd7.\n\nThis item can only be used in the [Great Marsh]{location} or [Safari Zone]{location}.',
        u'[Safari Zone]{location}',
    ): 'in a Safari Zone',
    (
        u'Used outside of battle\n:   Transports the trainer to the last-entered dungeon entrance.  Cannot be used outside, in buildings, or in [Distortion World]{location}, [Hall of Origin]{location}, [Spear Pillar]{location}, or [Turnback Cave]{location}.',
        u'[Hall of Origin]{location}',
    ): '[Hall of Origin]{location:hall-of-origin-1}',
    (
        u'Give to the [Wingull]{pokemon} on [Route 13]{location}, along with [Gram 2]{item} and [Gram 3]{item}, to receive [TM89]{item}.',
        u'[Route 13]{location}',
    ): u'[Route 13]{location:unova-route-13}',
    (
        u'Give to the [Wingull]{pokemon} on [Route 13]{location}, along with [Gram 1]{item} and [Gram 3]{item}, to receive [TM89]{item}.',
        u'[Route 13]{location}',
    ): u'[Route 13]{location:unova-route-13}',
    (
        u'Give to the [Wingull]{pokemon} on [Route 13]{location}, along with [Gram 1]{item} and [Gram 2]{item}, to receive [TM89]{item}.',
        u'[Route 13]{location}',
    ): u'[Route 13]{location:unova-route-13}',
    (
        u"Forms have different stats and movepools.  In Generation III, Deoxys's form depends on the game: Normal Forme in Ruby and Sapphire, Attack Forme in FireRed, Defense Forme in LeafGreen, and Speed Forme in Emerald.  In Generation IV, every form exists: form is preserved when transferring via [Pal Park]{location}, and meteorites in the southeast corner of [Veilstone City]{location} or at the west end of [Route 3]{location} can be used to switch between forms.",
        u'[Route 3]{location}',
    ): u'[Route 3]{location:kanto-route-13}',
}

def get_replacement(session, entire_text, matchobj):
    print "%-30s" % matchobj.group(0),
    label = matchobj.group('label')
    category = matchobj.group('category')
    target = matchobj.group('target') or label
    try:
        result = manual_replacements[entire_text, matchobj.group(0)]
    except KeyError:
        if category == 'mechanic':
            target = target.lower()
        else:
            query = None
            if category == 'item':
                table = tables.Item
            elif category == 'ability':
                table = tables.Ability
            elif category == 'move':
                table = tables.Move
            elif category == 'type':
                table = tables.Type
            elif category == 'pokemon':
                table = tables.Pokemon
                query = session.query(table).filter(tables.Pokemon.id < 10000)
            elif category == 'location':
                table = tables.Location
            else:
                print
                print repr(entire_text)
                print repr(matchobj.group(0))
                raise ValueError('Category %s not implemented' % category)
            if not query:
                query = session.query(table)
            query = query.join(table.names_local)
            query = query.filter(func.lower(table.names_table.name) == target.lower())
            try:
                thingy = query.one()
                target = thingy.identifier
            except:
                print
                print repr(entire_text)
                print repr(matchobj.group(0))
                raise
    result = "[%s]{%s:%s}" % (label, category, target)
    print result
    return result

def main(argv):
    session = connect()
    for cls in tables.mapped_classes:
        for translation_class in cls.translation_classes:
            columns = translation_class.__table__.c
            md_columns = [c for c in columns if c.info.get('format') == 'markdown']
            if not md_columns:
                continue
            for row in session.query(translation_class):
                if row.local_language_id != english_id:
                    continue
                for column in md_columns:
                    markdown = getattr(row, column.name)
                    if not markdown:
                        continue
                    text = unicode(markdown)
                    # Make sure everything that remotely looks like a link is one
                    links = fuzzy_link_re.findall(text)
                    if not links:
                        continue
                    for link in links:
                        assert strict_link_re.findall(link), [link]
                    # Do the replacement
                    replaced = strict_link_re.sub(
                            partial(get_replacement, session, text),
                            text,
                        )
                    setattr(row, column.name, replaced)

    if argv and argv[0] == '--commit':
        session.commit()
        print 'Committed'
    else:
        print 'Run with --commit to commit changes'

if __name__ == '__main__':
    main(sys.argv[1:])