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

from frozendict import frozendict
from init_helpers import Jsonable

from openapi_tools.spec.spec_resource import SpecResource, SpecRef
from .schema_format import StringSchemaFormat
from .type_schema import TypeSchema
from ..example import Example


@dataclass(frozen=True, slots=True)
class StringSchema(TypeSchema):
    type_: ClassVar[str] = "string"
    format_: StringSchemaFormat | None = None
    min_length: int | None = None
    max_length: int | None = None
    pattern: str = ''

    def get_spec_dict(self, dependency_to_ref: Mapping['SpecResource', SpecRef | dict]) -> frozendict[str, Jsonable]:
        result = {}
        if self.pattern:
            result['pattern'] = self.pattern
            if self.examples:
                if any(not (re.match(self.pattern, v := e.value)) for e in self.examples if isinstance(e, Example)):
                    raise ValueError(f'Example value: {v!r} does not match pattern: {self.pattern!r}')
        if self.min_length is not None:
            result |= {'minLength': self.min_length}
        if self.max_length is not None:
            result |= {'maxLength': self.max_length}
        return frozendict(TypeSchema.get_spec_dict(self, dependency_to_ref) | result)

    @functools.cache
    def _get_repr_parts(self) -> tuple[str, ...]:
        parts = list(TypeSchema._get_repr_parts(self))
        parts += [f'min_length={self.min_length!r}'] if self.min_length else []
        parts += [f'max_length={self.max_length!r}'] if self.max_length else []
        return tuple(parts)

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

    __str__ = __repr__
