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

from frozendict import frozendict
from init_helpers import Jsonable

from .spec_ref import SpecRef


@dataclass(frozen=True, slots=True)
class SpecResource(abc.ABC):
    @abc.abstractmethod
    def get_spec_dependencies(self) -> frozenset['SpecResource']:
        raise NotImplementedError

    @functools.cache
    def get_spec_dependencies_recursively(self) -> frozenset['SpecResource']:
        visited: set['SpecResource'] = set()
        pending = list(self.get_spec_dependencies())
        while pending:
            current = pending.pop()
            if current in visited:
                continue
            visited.add(current)
            pending.extend(current.get_spec_dependencies())
        return frozenset(visited)

    @abc.abstractmethod
    def get_spec_dict(self, dependency_to_ref: Mapping['SpecResource', SpecRef]) -> frozendict[str, Jsonable]:
        raise NotImplementedError

    def merge_spec_dict(
            self,
            dependency_to_ref: Mapping['SpecResource', SpecRef],
            present_value: frozendict[str, Jsonable]
    ) -> frozendict[str, Jsonable]:
        raise TypeError(f'{self!r} cannot be merged with {present_value!r}')
