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

from frozendict import frozendict
from init_helpers import Jsonable
from init_helpers import NoValue

from ..example import get_examples_as_dict, BaseExample
from ..maybe_referencable_resource import MaybeReferencableResource
from ..spec_resource import SpecResource, SpecRef


@dataclass(frozen=True, slots=True)
class BaseSchema(MaybeReferencableResource, ABC):
    spec_path: ClassVar[tuple[str]] = ['components', 'schemas']
    default: Jsonable | NoValue = field(default=NoValue, kw_only=True)
    description: str = field(default='', kw_only=True)
    examples: tuple[BaseExample, ...] | None = field(default=tuple(), kw_only=True)
    key: str | None = field(default=None, kw_only=True)
    enum: tuple[Jsonable] | None = field(default=None, kw_only=True)

    @property
    def has_default(self) -> bool:
        return self.default is not NoValue

    def get_spec_dependencies(self) -> frozenset['SpecResource']:
        return frozenset(self.examples) if self.examples else frozenset()

    def get_spec_dict(self, dependency_to_ref: Mapping['SpecResource', SpecRef]) -> frozendict[str, Jsonable]:
        result = {}
        result |= {'default': self.default} if self.default is not NoValue else {}
        result |= {'description': self.description} if self.description else {}
        result |= get_examples_as_dict(self.examples, dependency_to_ref)
        result |= {'enum': self.enum} if self.enum else {}
        return frozendict(result)

    def get_key(self) -> None:
        return self.key

    @functools.cache
    def _get_repr_parts(self) -> tuple[str, ...]:
        parts = []
        parts += [f'default={self.default!r}'] if self.default is not NoValue else []
        parts += [f'description={self.description!r}'] if self.description else []
        parts += [f'examples={self.examples!r}'] if self.examples else []
        parts += [f'key={self.key!r}'] if self.key else []
        parts += [f'enum={self.enum!r}'] if self.enum else []
        return tuple(parts)
