import re

variables = {}
functions = {}

def interpret_bebra_generator(code, log=None, show_popup=None):
    lines = code.strip().split('\n')
    total_lines = len(lines)
    i = 0

    def parse_arguments(arg_str):
        return [arg.strip() for arg in arg_str.split(',') if arg.strip()]
    
    def resolve(val):
        if val.isdigit():
            return int(val)
        elif val in variables:
            return variables[val]
        return val


    while i < total_lines:
        line = lines[i].strip()
        if not line or line.startswith("#"):
            i += 1
            continue

        # Команда clear — очистка консоли
        if line.strip() == "clear":
            if log:
                log("__clear__")  # Специальный сигнал
            i += 1
            yield ("continue", None)
            continue

       # Команда create
        if line.startswith("create"):
            parts = line.split()
            if len(parts) == 4 and parts[2] == "set":
                var_name = parts[1]
                value = resolve(parts[3])
                variables[var_name] = value
            else:
                yield ("error", f"Неправильный синтаксис create на строке {i+1}")
            i += 1
            continue

        # Команда make
        if line.startswith("make"):
            parts = line.split()
            if len(parts) == 4 and parts[2] == "set":
                target_var_name = resolve(parts[1])  # ← важное исправление
                value = resolve(parts[3])
                variables[target_var_name] = value
            else:
                yield ("error", f"Неправильный синтаксис make на строке {i+1}")
            i += 1
            continue

        # Команда smell
        m = re.match(r'smell\(\s*(text|numb)\s*,\s*(.+?)\s*,\s*(console|screen)\s*\)', line)
        if m:
            val_type, value, target = m.groups()
            if value.startswith('"') and value.endswith('"'):
                value = value[1:-1]
            elif val_type == "numb":
                value = str(variables.get(value, f"<неизв. переменная: {value}>"))
            elif val_type == "text":
                value = str(variables.get(value, f"<неизв. переменная: {value}>"))

            if target == "console" and log:
                log(str(value))
            elif target == "screen" and show_popup:
                show_popup(str(value))
            i += 1
            yield ("continue", None)
            continue

        # Команда wait(sec N) или wait(min N)
        m = re.match(r'wait\(\s*(sec|min)\s+(\d+)\s*\)', line)
        if m:
            unit, amount = m.groups()
            amount = int(amount)
            seconds = amount if unit == "sec" else amount * 60
            yield ("wait", seconds)
            i += 1
            continue

        # Определение функции
        if line.startswith("func") and line.endswith(":"):
            header = line[5:-1].strip()
            if "(" in header and ")" in header:
                name = header[:header.index("(")].strip()
                arg_str = header[header.index("(")+1:header.index(")")]
                args = parse_arguments(arg_str)
                i += 1
                body = []
                while i < total_lines and lines[i].startswith("    "):
                    body.append(lines[i][4:])
                    i += 1
                functions[name] = (args, body)
                continue

        # Вызов функции (пример: myfunc(1, 2))
        m = re.match(r'(\w+)\s*\((.*?)\)', line)
        if m:
            name = m.group(1)
            call_args = parse_arguments(m.group(2))
            if name not in functions:
                yield ("error", f"Функция '{name}' не найдена")
                return
            func_args, func_body = functions[name]
            if len(func_args) != len(call_args):
                yield ("error", f"Функция '{name}' ожидает {len(func_args)} аргументов, получено {len(call_args)}")
                return
            old_vars = variables.copy()
            for k, v in zip(func_args, call_args):
                if v.isdigit():
                    variables[k] = int(v)
                elif v in variables:
                    variables[k] = variables[v]
                else:
                    if v.startswith('"') and v.endswith('"'):
                        variables[k] = v[1:-1]  # строка
                    elif v.isdigit():
                        variables[k] = int(v)   # число
                    elif v in variables:
                        variables[k] = variables[v]  # переменная
                    else:
                        variables[k] = v  # просто текст

            sub_interpreter = interpret_bebra_generator("\n".join(func_body), log, show_popup)
            for step in sub_interpreter:
                yield step
            variables.update(old_vars)
            i += 1
            continue

        # Прочие строки — игнорируем
        i += 1
        yield ("continue", None)

    yield ("done", None)
