import json
import warnings
from copy import deepcopy
from importlib.resources import files
from typing import Any

from .. import RELAIData


class DataType(RELAIData):
    """Data model for a data type.

    Args:
        data_type (str): Type of the data. Must be one of "string", "integer", "float", "boolean", or "enum".
        options (list[str], optional): List of options for the data type. Defaults to None.
            Must be provided if `data_type` is "enum".
    """

    schema_file: str = files("relai_visualization").joinpath("schema/data/data-type.schema.json")

    def __init__(self, data_type: str, options: list[str] = None) -> None:
        # TODO: Drop support for "number" data type
        if data_type not in ["string", "integer", "float", "boolean", "enum", "number"]:
            raise ValueError("Invalid data type")
        if data_type == "number":
            warnings.warn(
                """'number' data type is deprecated and will be removed in a future version."""
                """Use 'integer' or 'float' instead. For now, 'number' is treated as 'float'.""",
                DeprecationWarning,
                stacklevel=2,
            )
            data_type = "float"
        if (data_type == "enum" and not options) or (options and data_type != "enum"):
            raise ValueError("Options must and only be provided for `enum` data type")
        if data_type == "enum" and len(options) < 2:
            raise ValueError("At least two options must be provided for `enum` data type")
        super().__init__(type=data_type, options=options)

    def __str__(self) -> str:
        output_dict = deepcopy(self.data)
        if self.data["type"] == "enum":
            output_dict["type"] = f"enum({self.data['options']})"
            del output_dict["options"]
        return json.dumps(output_dict)

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, DataType):
            return False
        return self.data == other.data

    def validate(self, value: Any) -> bool:
        """Check if the value is valid for the data type.

        Args:
            value (Any): Value to be validated.

        Returns:
            bool: True if the value is valid, False otherwise.
        """
        if self.data["type"] == "string":
            return isinstance(value, str)
        if self.data["type"] == "integer":
            return isinstance(value, int)
        if self.data["type"] == "float":
            return isinstance(value, float)
        if self.data["type"] == "boolean":
            return isinstance(value, bool)
        if self.data["type"] == "enum":
            return value in self.data["options"]
        return False

    @classmethod
    def from_dict(cls, data: dict) -> "DataType":
        """Create a data type from a dictionary."""
        return cls(data["type"], data.get("options"))
