"""System status domain models and enums."""

from __future__ import annotations

from enum import IntEnum

from pydantic import BaseModel, ConfigDict

from radiens_core.models.ports import GPIOChannelCount, Port, PortChannelCount

# ===================================================================
# System status enums
# ===================================================================


class BackboneMode(IntEnum):
    """Hardware backbone mode. Values match proto ``allego.BackboneMode``."""

    SMARTBOX_PRO = 0
    SMARTBOX_SIM_GEN_SINE = 1  # low freq
    SMARTBOX_SIM_GEN_SPIKES = 2
    SMARTBOX_SIM_DATASOURCE = 3
    OPEN_EPHYS_USB3 = 4
    INTAN_RECORDING_CONTROLLER_1024 = 5
    SMARTBOX_CLASSIC = 6
    INTAN_RECORDING_CONTROLLER_512 = 7
    OPEN_EPHYS_USB2 = 8
    INTAN_USB2 = 9
    SMARTBOX_SIM_GEN_SINE_MAPPED = 10
    SMARTBOX_SIM_GEN_SINE_HIGH_FREQ = 11
    SMARTBOX_SIM_GEN_SINE_MULTI_BAND = 12
    SMARTBOX_PRO_SINAPS_256 = 13
    SMARTBOX_PRO_SINAPS_1024 = 14
    XDAQ_ONE_REC = 15
    XDAQ_ONE_STIM = 16
    XDAQ_CORE_REC = 17
    XDAQ_CORE_STIM = 18
    SMARTBOX_PRO_SINAPS_512 = 19
    XDAQ_GEN2_ONE_STIM = 20
    XDAQ_GEN2_CORE_STIM = 21
    XDAQ_GEN2_ONE_REC = 22
    XDAQ_GEN2_CORE_REC = 23
    SMARTBOX_SIM_GEN_LFP = 24


class StreamMode(IntEnum):
    """Data stream mode. Values match proto ``allego.StreamMode``."""

    OFF = 0  # S_OFF
    ON = 1  # S_ON


class RecordMode(IntEnum):
    """Data recording mode. Values match proto ``allego.RecordMode``."""

    OFF = 0  # R_OFF
    ON = 1  # R_ON


class DataRecordingType(IntEnum):
    """Data recording type. Values match proto ``allego.DataRecordingType``."""

    CONTINUOUS = 0  # continuous
    SPIKES = 1  # spikes
    CONTINUOUS_AND_SPIKES = 2  # continuousAndSpikes


# ===================================================================
# Status models
# ===================================================================


class RestartRequest(BaseModel):
    """Request to restart the system with a specific backbone mode.

    Attributes:
        mode: Target hardware backbone mode. References BackboneMode.
    """

    model_config = ConfigDict(frozen=True)

    mode: BackboneMode


class RecordStateRequest(BaseModel):
    """Request to change recording state.

    Attributes:
        mode: Target recording mode. References RecordMode.
        port: Optional port to control. References Port. Defaults to None.
    """

    model_config = ConfigDict(frozen=True)

    mode: RecordMode
    port: Port | None = None  # If None, system-level record control


class StreamStateRequest(BaseModel):
    """Request to change streaming state.

    Attributes:
        mode: Target streaming mode. References StreamMode.
    """

    model_config = ConfigDict(frozen=True)

    mode: StreamMode


class StreamingStatus(BaseModel):
    """Current streaming status.

    Attributes:
        stream_mode: Current streaming mode. References StreamMode.
        primary_cache_t_range: Time range of data in the primary cache.
        hardware_memory_level: Hardware memory fill level (0.0 to 1.0).
    """

    model_config = ConfigDict(frozen=True)

    stream_mode: StreamMode
    primary_cache_t_range: list[float]
    hardware_memory_level: float


class RecordingStatus(BaseModel):
    """Current recording status.

    Attributes:
        record_mode: System-level recording mode. References RecordMode.
        active_filename: Name of the file currently being recorded.
        duration: Current recording duration in seconds.
        error: Current recording error message, if any.
        record_mode_port_a: Recording mode for Port A. References RecordMode. Defaults to None.
        record_mode_port_b: Recording mode for Port B. References RecordMode. Defaults to None.
        record_mode_port_c: Recording mode for Port C. References RecordMode. Defaults to None.
        record_mode_port_d: Recording mode for Port D. References RecordMode. Defaults to None.
        record_mode_port_e: Recording mode for Port E. References RecordMode. Defaults to None.
        record_mode_port_f: Recording mode for Port F. References RecordMode. Defaults to None.
        record_mode_port_g: Recording mode for Port G. References RecordMode. Defaults to None.
        record_mode_port_h: Recording mode for Port H. References RecordMode. Defaults to None.
    """

    model_config = ConfigDict(frozen=True)

    record_mode: RecordMode
    active_filename: str
    duration: float
    error: str
    record_mode_port_a: RecordMode | None = None
    record_mode_port_b: RecordMode | None = None
    record_mode_port_c: RecordMode | None = None
    record_mode_port_d: RecordMode | None = None
    record_mode_port_e: RecordMode | None = None
    record_mode_port_f: RecordMode | None = None
    record_mode_port_g: RecordMode | None = None
    record_mode_port_h: RecordMode | None = None


class RecordingConfig(BaseModel):
    """Recording configuration settings.

    Configures output file paths, naming, and recording behavior.
    Used as both request (for set_recording_config) and response (for get_recording_config).

    Attributes:
        base_file_name: Base filename for recording output (without extension or timestamp).
        base_file_path: Base directory path for recording files.
        datasource_idx: Index number for the composed file name. Defaults to 0.
        time_stamp: True to include timestamp in the composed file name. Defaults to True.
        split_files_by_port: True to create separate files for each port. Defaults to False.
        force_start_at_tstamp_0: True to force recording to start at timestamp 0. Defaults to False.
        recording_type: Type of data to record. References DataRecordingType. Defaults to DataRecordingType.CONTINUOUS.
    """

    model_config = ConfigDict(frozen=True)

    base_file_name: str
    base_file_path: str
    datasource_idx: int = 0
    time_stamp: bool = True
    split_files_by_port: bool = False
    force_start_at_tstamp_0: bool = False
    recording_type: DataRecordingType = DataRecordingType.CONTINUOUS


class BackboneStatus(BaseModel):
    """Complete system backbone status.

    Attributes:
        streaming: Current streaming status.
        recording: Current recording status.
        ports: List of port channel counts.
        is_connected: Whether the backbone is connected.
        gpio_channel_count: GPIO channel count information.
    """

    model_config = ConfigDict(frozen=True)

    streaming: StreamingStatus
    recording: RecordingStatus
    ports: list[PortChannelCount]
    is_connected: bool
    gpio_channel_count: GPIOChannelCount


class SinapsStatusRegisters(BaseModel):
    """Status registers for a Sinaps probe.

    Attributes:
        calibration_state: True if the probe is currently calibrating.
        calibration_progress: Calibration progress (0.0 to 1.0).
        num_active_pixels_shank0: Number of active pixels on shank 0.
        num_active_pixels_shank1: Number of active pixels on shank 1.
        num_active_pixels_shank2: Number of active pixels on shank 2.
        num_active_pixels_shank3: Number of active pixels on shank 3.
        v_ref_ffa: Reference voltage FFA.
        v_ref_ffb: Reference voltage FFB.
        v_ref_ffc: Reference voltage FFC.
        v_ref_ffd: Reference voltage FFD.
        is_error0: True if there is an error on shank 0.
        is_error1: True if there is an error on shank 1.
        is_error2: True if there is an error on shank 2.
        is_error3: True if there is an error on shank 3.
        host_counter: Host-side packet counter.
        fpga_counter: FPGA-side packet counter.
        firmware_version: Probe firmware version string.
        probe_generation: Probe hardware generation number.
        probe_model: Probe model number.
    """

    model_config = ConfigDict(frozen=True)

    calibration_state: bool
    calibration_progress: float
    num_active_pixels_shank0: int
    num_active_pixels_shank1: int
    num_active_pixels_shank2: int
    num_active_pixels_shank3: int
    v_ref_ffa: float
    v_ref_ffb: float
    v_ref_ffc: float
    v_ref_ffd: float
    is_error0: bool
    is_error1: bool
    is_error2: bool
    is_error3: bool
    host_counter: int
    fpga_counter: int
    firmware_version: str
    probe_generation: int
    probe_model: int
