import pathlib
import re
import subprocess
from dataclasses import dataclass, field

from utils import PROJECT_DIR, log, render_python_template

template = """# This file is auto-generated by gen_schema_exports.py
{% for file in data.module.files %}{{ file.import_str() }}
{% endfor %}

__all__ = [
    {% for file in data.module.files %}
    {%- for class in file.classes -%}
    "{{ class }}",
    {%- endfor -%}
    {%- endfor %}
]

"""

SCHEMA_PATH = PROJECT_DIR / "mealie" / "schema"

SKIP = {"static", "__pycache__"}


class PyFile:
    import_path: str
    """The import path of the file"""

    classes: list[str]
    """A list of classes in the file"""

    def __init__(self, path: pathlib.Path):
        self.import_path = path.stem
        self.classes = []

        self.classes = PyFile.extract_classes(path)
        self.classes.sort()

    def import_str(self) -> str:
        """Returns a string that can be used to import the file"""
        return f"from .{self.import_path} import {', '.join(self.classes)}"

    @staticmethod
    def extract_classes(file_path: pathlib.Path) -> list[str]:
        name = file_path.stem

        if name == "__init__" or name.startswith("_"):
            return []

        classes = re.findall(r"(?m)^class\s(\w+)", file_path.read_text())
        return classes


@dataclass
class Modules:
    directory: pathlib.Path
    """The directory to search for modules"""

    files: list[PyFile] = field(default_factory=list)
    """A list of files in the directory"""

    def __post_init__(self):
        for file in self.directory.glob("*.py"):
            if file.name.startswith("_"):
                continue

            pfile = PyFile(file)

            if len(pfile.classes) > 0:
                self.files.append(pfile)

            else:
                log.debug(f"Skipping {file.name} as it has no classes")


def find_modules(root: pathlib.Path) -> list[Modules]:
    """Finds all the top level modules in the provided folder"""
    modules: list[Modules] = []
    for file in root.iterdir():
        if file.is_dir() and file.name not in SKIP:
            modules.append(Modules(directory=file))

    return modules


def main() -> None:
    modules = find_modules(SCHEMA_PATH)

    template_paths: list[pathlib.Path] = []
    for module in modules:
        log.debug(f"Module: {module.directory.name}")
        for file in module.files:
            log.debug(f"  File: {file.import_path}")
            log.debug(f"    Classes: [{', '.join(file.classes)}]")

        template_path = module.directory / "__init__.py"
        template_paths.append(template_path)
        render_python_template(template, template_path, {"module": module})

    path_args = (str(p) for p in template_paths)
    subprocess.run(["uv", "run", "ruff", "check", *path_args, "--fix"])
    subprocess.run(["uv", "run", "ruff", "format", *path_args])


if __name__ == "__main__":
    main()
