from enum import Enum
from typing import Dict

import yaml
from dihttpmessageprocessor import AutoMappedDiRouterProcessorBuilder
from messageprocessor import MessageProcessor
from simplehttprouter import Route
from yaml.representer import BaseRepresenter

from ..interactor.dto import AutoOpenApiYamlBuilderRequest
from ..model import BaseModel, ServerModel
from ..model_builder import OpenApiModelBuilder


def represent_base_model(rep: BaseRepresenter, data: BaseModel | dict):
    if isinstance(data, BaseModel):
        data = data.get_model_data()
    return rep.represent_mapping('tag:yaml.org,2002:map', data)


def represent_enum(rep: BaseRepresenter, data: Enum):
    return rep.represent_scalar('tag:yaml.org,2002:str', data.value)


yaml.add_multi_representer(BaseModel, represent_base_model)
yaml.add_multi_representer(Enum, represent_enum)


class AutoOpenApiYamlBuilderInteractor:
    def __init__(
        self,
        router_processor_builder: AutoMappedDiRouterProcessorBuilder | None = None,
        routes: Dict[Route, MessageProcessor] | None = None
    ):
        self.router_processor_builder = router_processor_builder
        self.routes = routes

    def execute(self, request: AutoOpenApiYamlBuilderRequest) -> str:
        builder = OpenApiModelBuilder()
        model = builder.build_model()
        if request.host is not None:
            model.add_server(
                server=ServerModel(
                    url=request.host,
                )
            )
        if self.router_processor_builder is not None:
            for route, definition in self.router_processor_builder.auto_mapped_definition.items():
                builder.add_interactor_path(
                    model=model,
                    route=route,
                    interactor_type=definition.interactor_type,
                    request_type=definition.request_type,
                    response_content_type=definition.response_content_type,
                )

            for route, processor_type in self.router_processor_builder.route_definition.items():
                builder.add_processor_path(
                    model=model,
                    route=route,
                    processor=processor_type,
                )
        if self.routes is not None:
            for route, processor in self.routes.items():
                builder.add_processor_path(
                    model=model,
                    route=route,
                    processor=processor,
                )

        return yaml.dump(
            model,
            sort_keys=False,
        )
