import os
import re
from enum import Enum
from pathlib import Path

BASE_PATH = "lex-export/LexBot/BotLocales/en_US/Intents"
OUTPUT_PATH = "lambdas/fulfillment_function/src/fulfillment_function/classes"


def is_valid_enum_key(key: str) -> bool:
    """Check if a given key is a valid enum key."""
    return re.match(r"^[a-zA-Z_]\w*$", key) is not None


def get_intents(base_path: str) -> list[Path]:
    return [d for d in Path(base_path).iterdir() if d.is_dir()]


def get_slots(intent_path: Path) -> list[Path]:
    slots_dir = intent_path / "Slots"
    if slots_dir.exists() and slots_dir.is_dir():
        return [d for d in slots_dir.iterdir() if d.is_dir()]
    return []


def generate_enum_for_intent(intent_path: Path) -> type[Enum] | None:
    slots = get_slots(intent_path)
    if not slots:
        return None

    enum_name = intent_path.name.replace("_", "") + "Slot"

    slot_dict = {}
    for slot in slots:
        if not is_valid_enum_key(slot.name):
            raise ValueError(f"Invalid enum key detected: {slot.name}")
        slot_dict[slot.name] = slot.name

    # Create enum dynamically
    enum_cls = Enum(enum_name, slot_dict)  # type: ignore
    return enum_cls  # type: ignore


def regenerate_slot_enums(project_root="."):
    base_path = os.path.join(project_root, "lex-export/LexBot/BotLocales/en_US/Intents")
    intents = get_intents(base_path)

    enums = []
    for intent in intents:
        enum_cls = generate_enum_for_intent(intent)
        if enum_cls:
            enums.append(enum_cls)

    # Write to slot_enums.py
    output_path = os.path.join(project_root, "lambdas/fulfillment_function/src/fulfillment_function/classes")
    os.makedirs(output_path, exist_ok=True)
    with open(f"{output_path}/slot_enums.py", "w") as f:
        f.write("# Autogenerated by regenerate_enums.py. Do not edit.\n")
        f.write("from enum import Enum\n")
        f.write("from typing import Union\n")

        for enum in enums:  # type: ignore
            f.write(f"\n\nclass {enum.__name__}(Enum):\n")
            for item in enum:  # type: ignore
                f.write(f'    {item.name.upper()} = "{item.value}"\n')

        # Append the union type at the end
        union_entries = ",\n    ".join([e.__name__ for e in enums])  # type: ignore
        f.write(f"\n\nLexSlot = Union[\n    {union_entries}\n]")

        # Create the manual dispatching dict
        union_entries = ",\n    ".join(['"' + e.__name__ + '": ' + e.__name__ for e in enums])  # type: ignore
        f.write("\n\nLexSlot_Classes = " + "{" + f"\n    {union_entries}\n" + "}")


def regenerate_intent_enum(project_root="."):
    base_path = os.path.join(project_root, "lex-export/LexBot/BotLocales/en_US/Intents")
    output_path = os.path.join(project_root, "lambdas/fulfillment_function/src/fulfillment_function/classes")
    os.makedirs(output_path, exist_ok=True)

    with open(f"{output_path}/intent_name.py", "w") as f:
        f.write("# Autogenerated by regenerate_enums.py. Do not edit.\n")
        f.write("from enum import Enum\n")

        f.write("\n\nclass IntentName(Enum):\n")
        intents = get_intents(base_path)
        for intent in intents:
            if "\\" in str(intent):
                intent_name = str(intent).split("\\")[-1]
            else:
                intent_name = str(intent).split("/")[-1]

            f.write(f'    {intent_name.upper()} = "{intent_name}"\n')


if __name__ == "__main__":
    regenerate_intent_enum()
    regenerate_slot_enums()
