#  Copyright (C) 2025
#  ABM, Moscow
#
#  UNPUBLISHED PROPRIETARY MATERIAL.
#  ALL RIGHTS RESERVED.
#
#  Authors: Mike Orlov <m.orlov@abm-jsc.ru>
import functools
import itertools
from dataclasses import dataclass, field
from typing import Iterable, Mapping

from frozendict import frozendict
from init_helpers import Jsonable, AnyType

from .spec_ref import SpecRef
from .example import BaseExample, get_examples_as_dict
from .body_part_description import BodyPartDescription
from .spec_resource import SpecResource


@dataclass(frozen=True, slots=True)
class ContentSchema(SpecResource):
    """Media Type https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object"""
    schema: AnyType
    examples: Iterable[BaseExample] = tuple()
    # multipart only
    schema_key_to_description: Mapping[str, BodyPartDescription] = field(default_factory=frozendict)

    def __post_init__(self):
        object.__setattr__(self, 'examples', tuple(self.examples))
        object.__setattr__(self, 'schema_key_to_description', frozendict(self.schema_key_to_description))

    def get_spec_dependencies(self) -> frozenset[SpecResource]:
        # noinspection PyTypeChecker
        return frozenset(itertools.chain([self.schema], self.examples, self.schema_key_to_description.values()))

    def get_spec_dict(self, dependency_to_ref: Mapping[SpecResource | AnyType, SpecRef]) -> frozendict[str, Jsonable]:
        result = {"schema": dependency_to_ref[self.schema]}
        result |= get_examples_as_dict(self.examples, dependency_to_ref)
        if self.schema_key_to_description:
            result["encoding"] = {k: dependency_to_ref[d] for k, d in self.schema_key_to_description.items()}
        return frozendict(result)

    @functools.cache
    def _get_repr_parts(self) -> tuple[str, ...]:
        parts = [f'{self.schema.__name__ if isinstance(self.schema, type) else repr(self.schema)}']
        parts += [f'examples={self.examples!r}'] if self.examples else []
        if self.schema_key_to_description:
            parts += [f'schema_key_to_description={dict(self.schema_key_to_description)!r}']
        return tuple(parts)

    def __repr__(self):
        return f'{self.__class__.__name__}({", ".join(self._get_repr_parts())})'

    __str__ = __repr__
