import abc


class CalcCmdAbs(metaclass=abc.ABCMeta):
    def __init__(self, *args, **kwargs):
        self._args = args
        self._kwargs = kwargs

    @property
    @abc.abstractmethod
    def name(self):
        raise NotImplemented()

    def execute(self):
        raise NotImplemented()

from .interface import CalcCmdAbs

OPERATORS = list()


def register_operator(cls):
    OPERATORS.append(cls)
    return cls


@register_operator
class AddCmd(CalcCmdAbs):
    name = "add"

    def __init__(self, a, b):
        super().__init__(a, b)
        self.a = a
        self.b = b

    def execute(self):
        return self.a + self.b


@register_operator
class SubtractCmd(CalcCmdAbs):
    name = "subtract"

    def __init__(self, a, b):
        super().__init__(a, b)
        self.a = a
        self.b = b

    def execute(self):
        return self.a - self.b


class NoneCmd(CalcCmdAbs):
    name = "None Command"

    def execute(self):
        print("Invalid Command")

from .commands import OPERATORS, NoneCmd


def get_commands() -> dict:
    return dict([cmd.name, cmd] for cmd in OPERATORS)


def parse_commands(commands: dict, operation: str, *args):
    command = commands.setdefault(operation, NoneCmd)
    return command(*args)

import unittest

from .utils import get_commands, parse_commands


class TestCase(unittest.TestCase):

    def setUp(self) -> None:
        self.commands = get_commands()

    def test_addition(self):
        command = parse_commands(self.commands, "add", 1, 1)
        self.assertEqual(command.execute(), 2, "Addition fail")

    def test_subtraction(self):
        command = parse_commands(self.commands, "subtract", 1, 1)
        self.assertEqual(command.execute(), 0, "Subtraction fail")