from dataclasses import dataclass
from typing import Dict, List

from ._BaseModel import BaseModel
from ._RequestBodyModel import RequestBodyModel
from ._SchemaModel import SchemaModel
from ._SecuritySchemaModel import SecuritySchemaModel
from ..utils import set_dict_path_value, get_dict_path_value


@dataclass
class ComponentsModel(BaseModel):
    security_schemes: Dict[str, SecuritySchemaModel] = None
    request_bodies: Dict[str, RequestBodyModel] = None
    _schemas: Dict[str, SchemaModel] = None

    def add_security_scheme(self, name: str, model: SecuritySchemaModel):
        if self.security_schemes is None:
            self.security_schemes = {}
        self.security_schemes[name] = model

    def add_request_body(
        self,
        name: str,
        model: RequestBodyModel
    ):
        if self.request_bodies is None:
            self.request_bodies = {}
        self.request_bodies[name] = model

    def add_schema(self, model: SchemaModel):
        if self._schemas is None:
            self._schemas = {}

        set_dict_path_value(
            dict_value=self._schemas,
            path=[model.get_schema_uuid()],
            value=model
        )

    def get_schema(self, schema_uuid: str):
        return get_dict_path_value(
            dict_value=self._schemas,
            path=[schema_uuid]
        )

    def has_schema_name(self, schema_name: str) -> bool:
        if self._schemas is None:
            return False
        return any(
            s.get_schema_name() == schema_name
            for s in self._schemas.values()
        )

    def _build_schemas(self) -> dict:
        conflict_schemas: Dict[str, List[SchemaModel]] = {}
        ret = {}
        if self._schemas is not None:
            for schema in self._schemas.values():
                schema_name = schema.get_schema_name()
                if schema_name not in conflict_schemas:
                    conflict_schemas[schema_name] = []
                conflict_schemas[schema_name].append(schema)

        for schema_name in sorted(conflict_schemas.keys()):
            schemas = conflict_schemas[schema_name]
            conflicted = False
            if len(schemas) > 1:
                conflicted = True
            for schema in schemas:
                schema_name = schema.get_schema_name()
                if conflicted:
                    uuid = schema.get_schema_uuid()
                    if not schema_name.endswith(f"-{uuid}"):
                        schema_name = f"{schema_name}-{uuid}"
                        schema.set_schema_name(schema_name)
                ret[schema_name] = schema

        return dict(sorted(ret.items()))

    def to_dict(self) -> dict:
        return {
            **super().to_dict(),
            "schemas": self._build_schemas(),
        }
