import re

from rollbot import as_command, initialize_data, RollbotFailure, Message, Context
from rollbot.injection import Data, Args, Injector

for_pattern = re.compile(r"\bfor\b")


@initialize_data
class CurseScore:
    score: int = 0
    zero_passes: int = 0

    def touch(self):
        if self.score == 0:
            self.zero_passes += 1

    def __str__(self):
        return f"{self.score}{'!' * self.zero_passes}"


class Target(Injector[str]):
    async def inject(self, message: Message, context: Context) -> str:
        args = await Args.inject(message, context)
        key = re.split(for_pattern, args, maxsplit=1)[0].strip().replace(" ", "_").lower()
        if key == "":
            RollbotFailure.INVALID_ARGUMENTS.raise_exc(
                detail="I need to know who or what you're trying to curse!"
            )
        return key


@as_command
def karma(target: Target(), score: Data(CurseScore).For(Target())):
    return f"{target.capitalize()} = {score}"


@as_command
async def curse(target: Target(), store: Data(CurseScore)):
    score = await store.load_or(target)
    score.score -= 1
    score.touch()
    await store.save(target, score)
    return f"{target.capitalize()} = {score}"


@as_command
async def bless(target: Target(), store: Data(CurseScore)):
    score = await store.load_or(target)
    score.score += 1
    score.touch()
    await store.save(target, score)
    return f"{target.capitalize()} = {score}"


@as_command
async def blurse(target: Target(), store: Data(CurseScore)):
    score = await store.load_or(target)
    if abs(score.score) <= 1:
        score.zero_passes += 1
    await store.save(target, score)
    return f"{target.capitalize()} = {score}"
