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

import http_tools
import yarl
from init_helpers import custom_dumps, raise_if


@dataclass(frozen=True)
class BaseExample(abc.ABC):
    name: str = field(default='', kw_only=True)
    summary: str = field(default='', kw_only=True)
    description: str = field(default='', kw_only=True)

    def as_dict(self) -> dict[str, Any]:
        result = dataclasses.asdict(self)
        result.pop('name')
        if not self.summary:
            result.pop('summary')
        if not self.description:
            result.pop('description')
        return result


Jsonable = TypeVar('Jsonable')
Json = str


@dataclass(frozen=True)
class Example(BaseExample):
    val: InitVar[Jsonable]
    jsoner: Callable[[Jsonable], Json] = field(repr=False, compare=False, hash=False, default=custom_dumps)
    jsoned: str = field(init=False)

    def __post_init__(self, val: Jsonable) -> None:
        jsoned = self.jsoner(val)
        object.__setattr__(self, 'jsoned', jsoned)

    def as_dict(self) -> dict[str, Any]:
        result = super().as_dict()
        result.pop('jsoner')
        result.pop('jsoned')
        result['value'] = self.value
        return result

    @property
    def value(self) -> Jsonable:
        return json.loads(self.jsoned)

    def __str__(self) -> str:
        parts = [f'jsoned={self.jsoned}']
        parts += [f'name={self.name}'] if self.name else []
        parts += [f'summary={self.summary}'] if self.summary else []
        parts += [f'description={self.description}'] if self.description else []
        return f'{type(self).__name__}({", ".join(parts)})'

    __repr__ = __str__

@dataclass(frozen=True)
class RawExample(Example):
    def __post_init__(self, val: Jsonable):
        object.__setattr__(self, 'jsoned', val)


@dataclass(frozen=True)
class AnswerExample(BaseExample):
    answer: InitVar[http_tools.Answer]
    content_type: http_tools.ContentType | None = field(init=False)
    jsoned: str = field(init=False)

    def __post_init__(self, answer: http_tools.Answer):
        object.__setattr__(self, 'content_type', answer.content_type)
        raise_if(
            self.content_type != http_tools.ContentType.Json,
            NotImplementedError(f"Only Json is supported, got: {self.content_type}")
        )
        object.__setattr__(self, 'jsoned', answer.body.decode())

    @property
    def value(self) -> Jsonable:
        return json.loads(self.jsoned)


@dataclass(frozen=True)
class UriExample(BaseExample):
    external_value: yarl.URL
