#!/usr/bin/env python3
import os

COMMENT_PREFIX = "/// "

current_indent = 0
current_class = None
current_method = None
current_package = None


def split_to_parts(line, mod_desc=None):
    global current_indent
    global current_class
    global current_method
    global current_package

    if line.startswith("package: "):
        current_package = line[9:].strip()
        return

    if line.startswith("mock:global"):
        current_indent = 0
        current_class = None
        return

    if line.startswith("class "):
        current_class = line[6:].split("(")[0].strip(":")
        current_indent = 0

        yield (current_package, "\n")
        yield (current_package, "# " + mod_desc + "\n")

    elif line.startswith("def "):
        current_method = line[4:].split("(")[0]

        yield (current_package, "\n")

        if current_class is None:
            yield (current_package, "# " + mod_desc + "\n")
        else:
            current_indent = 4

    line = current_indent * " " + line

    yield (current_package, line)


def store_to_file(dest, parts):
    for package, line in parts:
        package = package.replace(".", "/")
        dirpath = os.path.join(os.path.abspath(dest), os.path.dirname(package))
        filename = os.path.basename(package) + ".py"

        if not os.path.exists(dirpath):
            os.makedirs(dirpath)
            open(os.path.join(dirpath, "__init__.py"), "w").close()
            open(os.path.join(dirpath, ".mock-generated"), "w").close()

        filepath = os.path.join(dirpath, filename)

        if not os.path.exists(filepath):
            with open(filepath, "a") as f:
                f.write("from typing import *\n")

        with open(filepath, "a") as f:
            f.write(line)


def build_module(mod_file, dest):
    global current_indent
    global current_class
    global current_package

    if not (mod_file.endswith(".h") or mod_file.endswith(".c")):
        return
    if not os.path.basename(mod_file).startswith("mod"):
        return

    current_indent = 0
    current_class = None
    current_package = (
        os.path.basename(mod_file).split(".")[0].split("-")[0].replace("mod", "")
    )
    mod_desc = mod_file.replace("../embed/extmod", "extmod")

    for l in open(mod_file):
        if not l.startswith(COMMENT_PREFIX):
            continue

        l = l[len(COMMENT_PREFIX) :]  # .strip()
        store_to_file(dest, split_to_parts(l, mod_desc))


def build_directory(dir, dest):
    print("Building mocks for", dir, "to", dest)
    for pkg in sorted(
        [x for x in os.listdir(dir) if os.path.isdir(os.path.join(dir, x))]
    ):
        for mod in sorted(os.listdir(os.path.join(dir, pkg))):
            build_module(os.path.join(dir, pkg, mod), dest)


def clear_directory(top_dir):
    print("Clearing up directory", top_dir)
    for root, dirs, files in os.walk(top_dir, topdown=False):
        if ".mock-generated" not in files:
            # print("Not a mock directory", root)
            continue
        for name in files:
            # print('Deleting file', os.path.join(root, name))
            os.remove(os.path.join(root, name))
        for name in dirs:
            # print('Deleting directory', os.path.join(root, name))
            try:
                os.rmdir(os.path.join(root, name))
            except FileNotFoundError:
                pass

        os.rmdir(root)


if __name__ == "__main__":
    clear_directory("../mocks/generated")
    build_directory("../embed/extmod", "../mocks/generated")