from bebra_commands import CreateCommand, MakeCommand, SmellCommand, WaitCommand

class ParseError(Exception):
    pass

class Parser:
    def __init__(self, tokens):
        self.tokens = tokens
        self.pos = 0

    def current(self):
        if self.pos < len(self.tokens):
            return self.tokens[self.pos]
        return None

    def eat(self, token_type, token_value=None):
        token = self.current()
        if token is None:
            raise ParseError(f"Unexpected end of input, expected {token_type}")
        if token.type != token_type:
            raise ParseError(f"Expected token type {token_type} but got {token.type} at line {token.line}")
        if token_value is not None and token.value != token_value:
            raise ParseError(f"Expected token value '{token_value}' but got '{token.value}' at line {token.line}")
        self.pos += 1
        return token

    def parse(self):
        commands = []
        while self.current() is not None:
            commands.append(self.parse_command())
        return commands

    def parse_command(self):
        token = self.current()
        if token.type == 'ID':
            if token.value == 'create':
                return self.parse_create()
            elif token.value == 'make':
                return self.parse_make()
            elif token.value == 'smell':
                return self.parse_smell()
            elif token.value == 'wait':
                return self.parse_wait()
            else:
                raise ParseError(f"Unknown command '{token.value}' at line {token.line}")
        else:
            raise ParseError(f"Unexpected token '{token.value}' at line {token.line}")

    def parse_create(self):
        self.eat('ID', 'create')
        var_name = self.eat('ID').value
        self.eat('ID', 'set')
        value_token = self.eat('NUMBER')
        return CreateCommand(var_name, value_token.value)

    def parse_make(self):
        self.eat('ID', 'make')
        var_name = self.eat('ID').value
        self.eat('ID', 'set')
        value_token = self.eat('NUMBER')
        return MakeCommand(var_name, value_token.value)

    def parse_smell(self):
        self.eat('ID', 'smell')
        self.eat('LPAREN')
        val_type = self.eat('ID').value
        self.eat('COMMA')
        var_name = self.eat('ID').value
        self.eat('COMMA')
        output = self.eat('ID').value
        self.eat('RPAREN')
        return SmellCommand(val_type, var_name, output)

    def parse_wait(self):
        self.eat('ID', 'wait')
        unit_token = self.eat('ID')
        amount_token = self.eat('NUMBER')
        return WaitCommand(unit_token.value, amount_token.value)
