"""Gold for missions, bigger/convertible Xenochip rewards."""
import re

from sc_lua import eol

MOD = {
    'id': 'quest_rewards',
    'name': 'Galactic Standards from missions',
    'description': 'Every mission that pays credits now also pays GS - the premium currency (only GS is visible on the mission board). '
                   'Xenochip rewards are multiplied (but they disappear for now...) and also converted into GS, and the mission card shows the GS. '
                   'Changes both quests.lua (what the card shows) and quests.xml (what the server pays).',
    'author': 'Furebel',
    'default_enabled': True,
    'order': 40,
    'files': {
        'lua': 'data/gamedata/shared/quests.lua',
        'xml': {'path': 'cloud/data/quests.xml', 'stage': 'xml'},
    },
    'tweakables': [
        {'key': 'gold_per_1000', 'type': 'float', 'default': 3.0, 'min': 0, 'max': 30, 'step': 0.5,
         'label': 'Gold per 1,000 credits of mission reward',
         'help': '3 means a 150,000-credit mission also pays 450 gold. 0 = no gold from credit rewards.'},
        {'key': 'xeno_multiplier', 'type': 'int', 'default': 20, 'min': 1, 'max': 50, 'step': 1,
         'label': 'Xenochip reward multiplier',
         'help': '1 = vanilla. 20 turns a 5-Xenochip mission into 100 Xenochips.'},
        {'key': 'gold_per_xenochip', 'type': 'int', 'default': 50, 'min': 0, 'max': 500, 'step': 5,
         'label': 'Gold per Xenochip (of the ORIGINAL reward)',
         'help': 'Xenochips vanish from the account in the offline game, so missions also pay gold for them. '
                 'Calculated from the vanilla amount, before the multiplier. 0 = off.'},
        {'key': 'show_gold', 'type': 'bool', 'default': True,
         'label': 'Show the gold amount on the mission card',
         'help': 'The card can only show one reward icon; credits are still paid even when it shows gold.'},
        {'key': 'task_easy', 'type': 'int', 'default': 100, 'min': 0, 'max': 2000, 'step': 10, 'advanced': True,
         'label': 'Gold for easy Regular Tasks that pay no credits',
         'help': 'Fallback for the higher-rank Regular Tasks that pay ore instead of credits.'},
        {'key': 'task_middle', 'type': 'int', 'default': 200, 'min': 0, 'max': 2000, 'step': 10, 'advanced': True,
         'label': 'Gold for medium Regular Tasks that pay no credits', 'help': ''},
        {'key': 'task_hard', 'type': 'int', 'default': 300, 'min': 0, 'max': 2000, 'step': 10, 'advanced': True,
         'label': 'Gold for hard Regular Tasks that pay no credits', 'help': ''},
    ],
}

QUEST_START = re.compile(r'^Quests\[\s*QuestId\.(\w+)\s*\]\s*=\s*\{')
GROUP = re.compile(r'group\s*=\s*QuestGroupId\.CHECKLIST_GROUP_\d')
EVENT = re.compile(r'game_event\s*=\s*ai\.GameEvent\.(\w+)')
VALUE = re.compile(r'required_value\s*=\s*([\d.]+)')
CREDITS = re.compile(r'^\s*reward_credits\s*=\s*(\d+)\s*,')
XENO_LINE = re.compile(r'^\s*reward_event_credits\s*=\s*(\d+)')
UI = re.compile(r'\s*ui_reward\s*=')
XML_TAG = re.compile(r'<Quest\s+id="\d+"[^>]*[^/]>')


def tier(block):
    ev, val = EVENT.search(block), VALUE.search(block)
    ev, val = (ev.group(1) if ev else ''), (float(val.group(1)) if val else 0)
    if ev == 'DEAL_DAMAGE' or (ev == 'TAKEDOWN' and val >= 30):
        return 'hard'
    if ev in ('EFFECTIVE_POINTS', 'TAKEDOWN') or (ev == 'PLAY_GAME' and val >= 2):
        return 'middle'
    return 'easy'


def gold_for(credits, xeno, regular_tier, v):
    gold = 0
    if credits and v['gold_per_1000'] > 0:
        gold += max(10, int(credits * v['gold_per_1000'] / 1000 / 10 + 0.5) * 10)
    elif regular_tier and not credits:
        gold += v['task_' + regular_tier]
    if xeno and v['gold_per_xenochip'] > 0:
        gold += xeno * v['gold_per_xenochip']
    return gold


def parse_lua(lines):
    starts = [i for i, l in enumerate(lines) if QUEST_START.match(l)] + [len(lines)]
    quests = []
    for a, b in zip(starts, starts[1:]):
        block = '\n'.join(lines[a:b])
        cr = next((CREDITS.match(lines[i]) for i in range(a, b) if CREDITS.match(lines[i])), None)
        xe = next((XENO_LINE.match(lines[i]) for i in range(a, b) if XENO_LINE.match(lines[i])), None)
        quests.append({
            'name': QUEST_START.match(lines[a]).group(1), 'a': a, 'b': b,
            'has_gold': 'reward_gold_credits' in block,
            'tier': tier(block) if GROUP.search(block) else None,
            'credits': int(cr.group(1)) if cr else 0,
            'xeno': int(xe.group(1)) if xe else 0,
        })
    return quests


def patch_lua(text, quests, v):
    lines = text.split('\n')
    inserts, swap, given = {}, set(), 0
    for q in quests:
        if q['has_gold']:
            continue
        gold = gold_for(q['credits'], q['xeno'], q['tier'], v)
        if gold <= 0:
            continue
        a, b = q['a'], q['b']
        spot = next((i for i in range(a, b) if UI.match(lines[i])), None)
        if spot is None:
            last = [i for i in range(a, b) if re.match(r'\s*reward_\w+\s*=', lines[i])]
            if not last:
                continue
            spot = last[-1] + 1
        inserts[spot] = '\treward_gold_credits = %d,%s' % (gold, eol(lines[spot]))
        given += 1
        if v['show_gold'] and UI.match(lines[spot]) and re.search(r'"reward_(credits|event_credits)"', lines[spot]):
            swap.add(spot)
    out = []
    for i, l in enumerate(lines):
        if i in inserts:
            out.append(inserts[i])
        out.append(re.sub(r'"reward_(credits|event_credits)"', '"reward_gold_credits"', l) if i in swap else l)
    text = '\n'.join(out)
    n_xeno = 0
    if v['xeno_multiplier'] != 1:
        def mul(m):
            nonlocal n_xeno
            n_xeno += 1
            return m.group(1) + str(int(m.group(2)) * v['xeno_multiplier'])
        text = re.sub(r'(?m)^(\s*reward_event_credits\s*=\s*)(\d+)', mul, text)
    return text, given, n_xeno


def set_attr(tag, name, value):
    if re.search(r'\b%s="[^"]*"' % name, tag):
        return re.sub(r'\b%s="[^"]*"' % name, '%s="%s"' % (name, value), tag)
    return tag[:-1].rstrip() + ' %s="%s">' % (name, value)


def patch_xml(text, quests, v):
    tiers = {q['name']: q['tier'] for q in quests}
    lua_gold = {q['name'] for q in quests if q['has_gold']}
    given = n_xeno = 0

    def repl(m):
        nonlocal given, n_xeno
        tag = m.group(0)
        name = re.search(r'\bname="(\w+)"', tag)
        if not name:
            return tag
        name = name.group(1)
        cr = re.search(r'\brewardCredits="(\d+)"', tag)
        xe = re.search(r'\brewardEventCredits="(\d+)"', tag)
        credits, xeno = int(cr.group(1)) if cr else 0, int(xe.group(1)) if xe else 0
        if name not in lua_gold:
            gold = gold_for(credits, xeno, tiers.get(name), v)
            if gold > 0:
                tag = set_attr(tag, 'rewardGoldCredits', gold)
                given += 1
        if xe and v['xeno_multiplier'] != 1:
            tag = set_attr(tag, 'rewardEventCredits', xeno * v['xeno_multiplier'])
            n_xeno += 1
        return tag

    return XML_TAG.sub(repl, text), given, n_xeno


def apply(files, v, log):
    quests = parse_lua(files['lua'].split('\n'))
    files['lua'], g1, x1 = patch_lua(files['lua'], quests, v)
    log('quests.lua: gold added to %d quests, Xenochips multiplied in %d' % (g1, x1))
    files['xml'], g2, x2 = patch_xml(files['xml'], quests, v)
    log('quests.xml: gold set on %d quests, Xenochips multiplied in %d' % (g2, x2))
