import dataclasses
import enum
import sys

import sila

if sys.version_info < (3, 12):
    import typing_extensions as typing
else:
    import typing


T = typing.TypeVar("T", bound=sila.Native)


@dataclasses.dataclass
class Enum(sila.Constrained[str]):
    """Enum data type that converts from and to a python enum."""

    _enum: typing.ClassVar[enum.EnumMeta] = enum.Enum

    @typing.override
    @classmethod
    def create(cls, enum_type: enum.EnumMeta) -> type[typing.Self]:
        data_type = super().create(
            sila.String, [sila.Set(values=[sila.String(cls._name_to_value(name)) for name in enum_type.__members__])]
        )
        data_type._enum = enum_type

        return data_type

    @typing.override
    @classmethod
    async def from_native(
        cls,
        context: "sila.Context",
        value: enum.Enum | None = None,
        /,
        *,
        execution: sila.framework.common.Execution | None = None,
    ) -> typing.Self:
        name = cls._name_to_value(value.name) if value is not None else None

        return await super().from_native(context, name, execution=execution)

    @typing.override
    async def to_native(self, context: "sila.Context", /) -> enum.EnumMeta:
        value = await super().to_native(context)
        name = next(name for name in self._enum.__members__ if self._name_to_value(name) == value)

        return self._enum[name]

    @classmethod
    def _name_to_value(cls, name: str) -> str:
        """Convert the enum name to a native string value."""
        return name.lower().replace("_", " ")
