"""KPI (Key Performance Indicator) signal metrics domain models and enums."""

from __future__ import annotations

from enum import IntEnum

import numpy as np
import numpy.typing as npt
from pydantic import BaseModel, ConfigDict

from radiens_core.models.signals import SignalType
from radiens_core.models.time_range import TimeRange


class KpiMode(IntEnum):
    """KPI computation mode. Values match proto ``common.KpiMetricsMode``."""

    BASE = 0
    AVG = 1
    STREAM = 2


class KpiMetric(IntEnum):
    """KPI metric identifier. Values match proto ``common.KpiMetricsEnum``."""

    NUM_PTS = 0
    NUM_PTS_ISI = 1
    DUR_SEC = 2
    MEAN = 3
    MIN = 4
    MIN_ISI = 5
    MAX = 6
    MAX_ISI = 7
    MAX_ABS = 8
    MAX_ABS_ISI = 9
    TIMESTAMP_MIN = 10
    TIMESTAMP_MAX = 11
    MAX_MIN_DIFF_ABS = 12
    MAX_MIN_DIFF_ABS_ISI = 13
    SD = 14
    SD_ISI = 15
    VAR = 16
    VAR_ISI = 17
    RMS = 18
    RMS_ISI = 19
    NOISE_UV = 20
    SNR = 21
    NUM_EVENTS = 22
    EVENT_RATE = 23
    EVENT_MAX = 24
    EVENT_MIN = 25
    EVENT_MAX_ABS = 26
    EVENT_MAX_MIN_DIFF_ABS = 27
    EVENT_TIMESTAMP_MIN = 28
    EVENT_TIMESTAMP_MAX = 29
    EVENT_TIMESTAMP_MAX_ABS = 30
    EVENT_TIMESTAMP_MAX_MIN_DIFF_ABS = 31
    MEAN_MAX = 32
    MEAN_MIN = 33
    MEAN_MAX_ABS = 34
    EVENT_MEAN_MAX_MIN_DIFF_ABS = 35
    MAX_MIN_DIFF_ABS_AMPLIFIED = 36


class KpiMetricId(BaseModel):
    """Identifies a single KPI metric (mode + name pair).

    Attributes:
    mode
        The computation mode (BASE, AVG, or STREAM).
    name
        The metric to compute.
    """

    model_config = ConfigDict(frozen=True)

    mode: KpiMode
    name: KpiMetric


class KpiMetricsResult(BaseModel):
    """Result of a KPI metrics query.

    ``values`` is a 2-D numpy array of shape ``(n_channels, n_metrics)``
    where rows correspond to ``channel_indices`` and columns to ``metrics``.

    Attributes:
    channel_indices
        Native channel indices (ntvIdxs) in row order.
    metrics
        KPI metric IDs in column order.
    signal_type
        Signal type for all channels in this result.
    values
        Metric values: shape ``(n_channels, n_metrics)``.
    time_range
        Time range over which these metrics were computed.
    """

    model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True)

    channel_indices: tuple[int, ...]
    metrics: tuple[KpiMetricId, ...]
    signal_type: SignalType
    values: npt.NDArray[np.float64]
    time_range: TimeRange


class KpiStatus(BaseModel):
    """Status of the KPI computation cache.

    Attributes:
    stream_group_id
        Stream group or datasource ID this status belongs to.
    num_packets_memory
        Number of KPI packets held in memory.
    packet_dur
        Duration of each KPI packet in seconds.
    update_period
        How often the KPI cache is updated, in seconds.
    persistence
        Exponential averaging persistence factor.
    beta
        Beta parameter for the averaging filter.
    is_tracking_signal_cache
        Whether the KPI cache is currently tracking the live signal cache.
    num_packets
        Total number of packets processed.
    memory_bytes
        Approximate memory used by the KPI cache in bytes.
    num_sigs
        Number of signals being tracked (``None`` if not yet active).
    time_range
        Time range covered by the current KPI cache (``None`` if not yet active).
    """

    model_config = ConfigDict(frozen=True)

    stream_group_id: str
    num_packets_memory: int
    packet_dur: float
    update_period: float
    persistence: float
    beta: float
    is_tracking_signal_cache: bool
    num_packets: int
    memory_bytes: float
    num_sigs: int | None = None
    time_range: TimeRange | None = None
