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

import yaml


class YAMLBase:
    def load(self, dictionary: dict) -> None:
        class_name = self.__class__.__name__
        for key, value in dictionary.items():
            if key not in self.keys():
                raise ValueError(f"Key [{key}] not in [{class_name}]")
            exists_value = getattr(self, key)
            if exists_value != value:
                logging.info(f'Change {class_name}.{key} from {exists_value} to {value}')
                setattr(self, key, value)

    def export(self) -> dict:
        dictionary = {}
        for key in self.keys():
            dictionary[key] = getattr(self, key)
        return dictionary

    def keys(self) -> list:
        return getattr(self, '_keys')

    def set_keys(self, keys: list) -> None:
        setattr(self, '_keys', keys)


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


class {class_name}(yaml_to_object.YAMLBase):
    def __init__(self, dictionary: dict = None):
        {initialization}

        self.set_keys({keys})
        if dictionary is not None:
            self.load(dictionary)
"""


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)

    return True


__all__ = ['generate', 'YAMLBase']
