from typing import Union, Dict, Optional, Any
from Controllers.Redis.base import RedisRow


class RedisResponse:
    """
    Base class for Redis response handling.

    Provides a standardized way to return and process Redis operation results,
    with tools to convert between different data representations.
    """

    def __init__(
        self,
        status: bool,
        message: str,
        data: Any = None,
        error: Optional[str] = None,
    ):
        """
        Initialize a Redis response.

        Args:
            status: Operation success status
            message: Human-readable message about the operation
            data: Response data (can be None, RedisRow, list, or dict)
            error: Optional error message if operation failed
        """
        self.status = status
        self.message = message
        self.data = data
        self.error = error

        # Determine the data type
        if isinstance(data, dict):
            self.data_type = "dict"
        elif isinstance(data, list):
            self.data_type = "list"
        elif isinstance(data, RedisRow):
            self.data_type = "row"
        elif isinstance(data, (int, float, str, bool)):
            self.data_type = "primitive"
        else:
            self.data_type = None

    def as_dict(self) -> Dict:
        """
        Convert the response to a dictionary format suitable for serialization.

        Returns:
            Dictionary representation of the response
        """
        # Base response fields
        main_dict = {
            "status": self.status,
            "message": self.message,
            "count": self.count,
            "dataType": self.data_type,
        }

        # Add error if present
        if self.error:
            main_dict["error"] = self.error

        data = self.all

        # Process single RedisRow
        if isinstance(data, RedisRow):
            result = {**main_dict}
            if hasattr(data, "keys") and hasattr(data, "row"):
                if not isinstance(data.keys, str):
                    raise ValueError("RedisRow keys must be string type")
                result[data.keys] = data.row
            return result

        # Process list of RedisRows
        elif isinstance(data, list):
            result = {**main_dict}

            # Handle list of RedisRow objects
            rows_dict = {}
            for row in data:
                if (
                    isinstance(row, RedisRow)
                    and hasattr(row, "keys")
                    and hasattr(row, "row")
                ):
                    if not isinstance(row.keys, str):
                        raise ValueError("RedisRow keys must be string type")
                    rows_dict[row.keys] = row.row

            if rows_dict:
                result["data"] = rows_dict
            elif data:  # If it's just a regular list with items
                result["data"] = data

            return result

        # Process dictionary
        elif isinstance(data, dict):
            return {**main_dict, "data": data}

        return main_dict

    @property
    def all(self) -> Any:
        """
        Get all data from the response.

        Returns:
            All data or empty list if None
        """
        return self.data if self.data is not None else []

    @property
    def count(self) -> int:
        """
        Count the number of items in the response data.

        Returns:
            Number of items (0 if no data)
        """
        data = self.all

        if isinstance(data, list):
            return len(data)
        elif isinstance(data, (RedisRow, dict)):
            return 1
        return 0

    @property
    def first(self) -> Union[Dict, None]:
        """
        Get the first item from the response data.

        Returns:
            First item as a dictionary or None if no data
        """
        if not self.data:
            return None

        if isinstance(self.data, list) and self.data:
            item = self.data[0]
            if isinstance(item, RedisRow) and hasattr(item, "row"):
                return item.row
            return item
        elif isinstance(self.data, RedisRow) and hasattr(self.data, "row"):
            return self.data.row
        elif isinstance(self.data, dict):
            return self.data

        return None

    def is_successful(self) -> bool:
        """
        Check if the operation was successful.

        Returns:
            Boolean indicating success status
        """
        return self.status

    def to_api_response(self) -> Dict:
        """
        Format the response for API consumption.

        Returns:
            API-friendly response dictionary
        """
        try:
            response = {
                "success": self.status,
                "message": self.message,
            }

            if self.error:
                response["error"] = self.error

            if self.data is not None:
                if self.data_type == "row" and hasattr(self.data, "to_dict"):
                    response["data"] = self.data.to_dict()
                elif self.data_type == "list":
                    try:
                        if all(hasattr(item, "to_dict") for item in self.data):
                            response["data"] = [item.to_dict() for item in self.data]
                        else:
                            response["data"] = self.data
                    except Exception as e:
                        response["error"] = f"Error converting list items: {str(e)}"
                else:
                    response["data"] = self.data

            response["count"] = self.count
            return response
        except Exception as e:
            return {
                "success": False,
                "message": "Error formatting response",
                "error": str(e),
            }
