from ..helpers import nativestr
from .utils import list_to_dict

# Mapping from RESP3 camelCase field names to the legacy snake_case
# attribute names. Used so callers can fetch the same value with either
# spelling regardless of which wire format produced the ``TSInfo``.
_FIELD_ALIASES = {
    "sourceKey": "source_key",
    "chunkCount": "chunk_count",
    "memoryUsage": "memory_usage",
    "totalSamples": "total_samples",
    "retentionTime": "retention_msecs",
    "lastTimestamp": "last_timestamp",
    "firstTimestamp": "first_timestamp",
    "maxSamplesPerChunk": "max_samples_per_chunk",
    "chunkSize": "chunk_size",
    "duplicatePolicy": "duplicate_policy",
}


class TSInfo:
    """
    Hold information and statistics on the time-series.
    Can be created using ``tsinfo`` command
    https://redis.io/docs/latest/commands/ts.info/

    Handles both RESP2 (flat list) and RESP3 (dict) responses.
    """

    rules = []
    labels = []
    sourceKey = None
    chunk_count = None
    memory_usage = None
    total_samples = None
    retention_msecs = None
    last_time_stamp = None
    first_time_stamp = None

    max_samples_per_chunk = None
    chunk_size = None
    duplicate_policy = None

    def __init__(self, args):
        """
        Hold information and statistics on the time-series.

        The supported params that can be passed as args:

        rules:
            A list of compaction rules of the time series.
        sourceKey:
            Key name for source time series in case the current series
            is a target of a rule.
        chunkCount:
            Number of Memory Chunks used for the time series.
        memoryUsage:
            Total number of bytes allocated for the time series.
        totalSamples:
            Total number of samples in the time series.
        labels:
            A list of label-value pairs that represent the metadata
            labels of the time series.
        retentionTime:
            Retention time, in milliseconds, for the time series.
        lastTimestamp:
            Last timestamp present in the time series.
        firstTimestamp:
            First timestamp present in the time series.
        maxSamplesPerChunk:
            Deprecated.
        chunkSize:
            Amount of memory, in bytes, allocated for data.
        duplicatePolicy:
            Policy that will define handling of duplicate samples.

        Can read more about on
        https://redis.io/docs/latest/develop/data-types/timeseries/configuration/#duplicate_policy
        """
        if isinstance(args, dict):
            # RESP3 wire: response is a native map.
            response = args
            self.rules = response.get("rules") or {}
            self.labels = response.get("labels") or {}
        else:
            # RESP2 wire: flat list of alternating key-value pairs.
            response = dict(zip(map(nativestr, args[::2]), args[1::2]))
            self.rules = response.get("rules")
            self.labels = list_to_dict(response.get("labels"))
        self.source_key = response.get("sourceKey")
        self.chunk_count = response.get("chunkCount")
        self.memory_usage = response.get("memoryUsage")
        self.total_samples = response.get("totalSamples")
        self.retention_msecs = response.get("retentionTime")
        self.last_timestamp = response.get("lastTimestamp")
        self.first_timestamp = response.get("firstTimestamp")
        if "maxSamplesPerChunk" in response:
            self.max_samples_per_chunk = response["maxSamplesPerChunk"]
            self.chunk_size = (
                self.max_samples_per_chunk * 16
            )  # backward compatible changes
        if "chunkSize" in response:
            self.chunk_size = response["chunkSize"]
        if "duplicatePolicy" in response:
            self.duplicate_policy = response["duplicatePolicy"]
            if isinstance(self.duplicate_policy, bytes):
                self.duplicate_policy = self.duplicate_policy.decode()

    def get(self, item):
        try:
            return self.__getitem__(item)
        except AttributeError:
            return None

    def __getitem__(self, item):
        return getattr(self, _FIELD_ALIASES.get(item, item))
