from typing import Union

from pydash import group_by

from .helper import oneline, tab
from .models.generation_detail import (GenerationClassDetail, GenerationImportModuleDetail, GenerationMethodDetail,
                                       GenerationPropertyDetail)


class Generation:
    def generate(self, class_detail: GenerationClassDetail):
        return self.generate_class(class_detail)

    def generate_import_modules(self, list_import_module: list[GenerationImportModuleDetail]):
        content = ''
        import_modules = group_by(list_import_module, 'module')
        for key in import_modules.keys():
            types = map(lambda import_module: import_module.type, import_modules[key])
            content += oneline(f'from {key} import {",".join(types)}')
        return content

    def generate_class(self, class_detail: GenerationClassDetail):
        parent_name = f'({class_detail.parent_name})' if class_detail.parent_name else ''
        content = oneline('@dataclass') if class_detail.is_dataclass else ''
        content += oneline(f'class {class_detail.class_name}{parent_name}:')
        content += self.generate_properties(class_detail.properties)
        content += self.generate_methods(class_detail.methods)
        return content

    def generate_methods(self, methods: list[GenerationMethodDetail]):
        content = ''
        for method in methods:
            content += tab(self.generate_method(method))
            content += '\r\n'
        return content

    def get_default_param_value(self, param_type: str):
        if param_type == 'Optional':
            return '= None'

        return ''

    def generate_method(self, method: GenerationMethodDetail):
        paramList = ", ".join(
            map(lambda param: f'{param.name}: {param.type} {self.get_default_param_value(param.type)}', method.params)
        )
        content = oneline(
            f'async def {method.name}(self, {paramList}, option: MicroserviceOption = None) -> {method.response}:'
        )
        content += oneline(tab(method.body))

        return content

    def generate_properties(self, properties: list[GenerationPropertyDetail]):
        content = ''
        for property in properties:
            content += tab(self.generate_property(property))
            content += '\r\n'
        return content

    def generate_enum_value(self, value: Union[int, str]):
        if isinstance(value, int):
            return value

        return f"'{value}'"

    def generate_property(self, property: GenerationPropertyDetail):
        if property.is_enum:
            return f"{property.name} = {self.generate_enum_value(property.default_value)}"

        content = f'{property.name}: {property.type}' if property.type else property.name

        fields = list()
        if property.default_value:
            fields.append(f'default={property.default_value}')
        if property.default_value is None and property.allow_none:
            fields.append(f'default=None')
        elif property.default_factory:
            fields.append(f'default_factory={property.default_factory}')

        if fields:
            content += f'=Field({",".join(fields)})'

        return content
