from pathlib import Path

from jinja2 import Template
from pydantic2ts import generate_typescript_defs
from utils import log

# ============================================================

template = """// This Code is auto generated by gen_global_components.py
{% for name in global %}import {{ name }} from "@/components/global/{{ name }}.vue";
{% endfor %}{% for name in layout %}import {{ name }} from "@/components/layout/{{ name }}.vue";
{% endfor %}
declare module "vue" {
  export interface GlobalComponents {
    // Global Components
{% for name in global -%}
    {{ "    " }}{{ name }}: typeof {{ name }};
{% endfor -%}
    {{ "    " }}// Layout Components
{% for name in layout -%}
    {{ "    " }}{{ name }}: typeof {{ name }};
{% endfor -%}{{ "  }"}}
}

export {};

"""

CWD = Path(__file__).parent
PROJECT_DIR = Path(__file__).parent.parent.parent


def generate_global_components_types() -> None:
    destination_file = PROJECT_DIR / "frontend" / "types" / "components.d.ts"

    component_paths = {
        "global": PROJECT_DIR / "frontend" / "components" / "global",
        "layout": PROJECT_DIR / "frontend" / "components" / "Layout",
    }

    def render_template(template: str, data: dict) -> str | None:
        tmpl = Template(template)
        return tmpl.render(**data)

    def build_data() -> dict:
        data = {}
        for name, path in component_paths.items():
            components = [component.stem for component in path.glob("*.vue")]
            components.sort()
            data[name] = components

        return data

    def write_template(text: str) -> None:
        destination_file.write_text(text)

    text = render_template(template, build_data())

    if text:
        write_template(text)


# ============================================================
# Pydantic To Typescript Generator


def generate_typescript_types() -> None:
    def path_to_module(path: Path):
        str_path: str = str(path)

        str_path = str_path.removeprefix(str(PROJECT_DIR))
        str_path = str_path.removeprefix("/")
        str_path = str_path.replace("/", ".")

        return str_path

    schema_path = PROJECT_DIR / "mealie" / "schema"
    types_dir = PROJECT_DIR / "frontend" / "lib" / "api" / "types"

    ignore_dirs = ["__pycache__", "static", "_mealie"]

    skipped_files: list[Path] = []
    skipped_dirs: list[Path] = []
    failed_modules: list[Path] = []

    for module in schema_path.iterdir():
        if module.is_dir() and module.stem in ignore_dirs:
            skipped_dirs.append(module)
            continue

        if not module.is_dir() or not module.joinpath("__init__.py").is_file():
            skipped_files.append(module)
            continue

        ts_out_name = module.name.replace("_", "-") + ".ts"
        out_path = types_dir.joinpath(ts_out_name)

        try:
            path_as_module = path_to_module(module)
            generate_typescript_defs(path_as_module, str(out_path), exclude=("MealieModel"))  # type: ignore
        except Exception as e:
            failed_modules.append(module)
            log.error(f"Module Error: {e}")

    log.debug("\n📁 Skipped Directories:")
    for skipped_dir in skipped_dirs:
        log.debug(f"   📁 {skipped_dir.name}")

    log.debug("📄 Skipped Files:")
    for f in skipped_files:
        log.debug(f"   📄 {f.name}")

    if len(failed_modules) > 0:
        log.error("❌ Failed Modules:")
        for f in failed_modules:
            log.error(f"   ❌ {f.name}")


def main():
    log.debug("\n-- Starting Global Components Generator --")
    generate_global_components_types()

    log.debug("\n-- Starting Pydantic To Typescript Generator --")
    generate_typescript_types()


if __name__ == "__main__":
    main()
