"""Utility functions for Additive Manufacturing provider.

We reuse GA offline numeric trimming style and offer simple smoothing and
robust scaling to keep parity with other demo apps.
"""

import numpy as np


def trim_data(record_data, trim_1=None, trim_2=None):
    """
    Trim record data based on numeric index boundaries.
    """
    signals = []
    for signal in record_data.get("signals", []):
        data = signal["data"]
        times = signal["times"]
        i1 = trim_1
        i2 = trim_2
        if i1 is not None and i2 is not None:
            data = data[i1:i2]
            times = times[i1:i2]
        elif i1 is not None:
            data = data[i1:]
            times = times[i1:]
        elif i2 is not None:
            data = data[:i2]
            times = times[:i2]
        signal["data"] = data
        signal["times"] = times
        signals.append(signal)
    record_data["signals"] = signals
    return record_data


def simple_moving_average(_record_name, _signal_name, raw_signal, _times, parameters):
    data = np.array(raw_signal)
    window_size = parameters.get(
        "simple_moving_average_moving_average_window_size",
        parameters.get("moving_average_window_size", 5),
    )
    window_size = int(max(1, min(window_size, len(data) if len(data) > 0 else 1)))
    weights = np.ones(window_size) / window_size
    smoothed = np.convolve(data, weights, mode="valid")
    pad = window_size - 1
    left = np.full(pad // 2, smoothed[0]) if smoothed.size else np.array([])
    right = np.full(pad - pad // 2, smoothed[-1]) if smoothed.size else np.array([])
    return np.concatenate([left, smoothed, right]) if smoothed.size else data


def robust_scaling(_record_name, _signal_name, raw_signal, _times, _parameters):
    data = np.asarray(raw_signal)
    if data.size == 0:
        return data
    median = np.median(data)
    q1, q3 = np.percentile(data, [25, 75])
    iqr = q3 - q1
    if iqr == 0:
        # fallback
        std = np.std(data)
        iqr = std if std != 0 else 1.0
    scaled = (data - median) / iqr
    return np.clip(scaled, -1e6, 1e6)


