from pathlib import Path
from typing import List, Dict, Any

import yaml

base_class = """# Generated by YAML-to-object (https://github.com/FebruaryBreeze/yaml-to-object)
class YAMLBase:
    def load(self, dictionary: dict):
        for key, value in dictionary.items():
            if key not in self._keys:
                raise ValueError(f"Load Key [{key}] not in [{self.__class__.__name__}]")
            setattr(self, key, value)

    def export(self):
        dictionary = {}
        for key in self._keys:
            dictionary[key] = getattr(self, key)
        return dictionary
"""

class_template = """# Generated by YAML-to-object (https://github.com/FebruaryBreeze/yaml-to-object)
from .yaml_base import YAMLBase


class {class_name}(YAMLBase):
    def __init__(self):
        self._keys = {keys}
        {initialization}
"""


def generate_class(class_name: str, dictionary: dict) -> str:
    initialization = '\n        '.join(
        f'self.{key}: {type(value).__name__} = {repr(value)}' for key, value in dictionary.items()
    )
    return class_template.format(class_name=class_name, initialization=initialization, keys=list(dictionary.keys()))


def lazy_write(file_path: Path, content: str):
    if file_path.exists():
        with open(str(file_path)) as f:
            exists_content = f.read()
        if exists_content == content:
            return

    with open(str(file_path), 'w') as f:
        f.write(content)


def generate(file_path: Path, suffix: str = '') -> bool:
    with open(str(file_path)) as f:
        content: Dict[str, Dict[str, Any]] = yaml.load(f)

    root: Path = file_path.parent / 'build'
    root.mkdir(exist_ok=True)

    init_list: List[str] = []
    for key, value in content.items():
        class_name = key.replace('_', ' ').title().replace(' ', '') + suffix.capitalize()
        class_content = generate_class(class_name=class_name, dictionary=value)

        file_name = key if not suffix else f'{key}_{suffix}'
        generate_path = root / f'{file_name}.py'
        lazy_write(file_path=generate_path, content=class_content)

        init_list.append(f'from .{generate_path.stem} import {class_name}')

    init_content = '\n'.join(init_list) + '\n'
    lazy_write(file_path=root / '__init__.py', content=init_content)
    lazy_write(file_path=root / 'yaml_base.py', content=base_class)

    return True
