"""Tests for math expressions and resultant computation."""

import numpy as np
import pytest

from impakt.transform.math_expr import math_expr
from impakt.transform.resultant import resultant_from_channels
from impakt.transform.resample import trim, resample


class TestMathExpr:
    def test_simple_expression(self, head_accel_x, head_accel_z):
        result = math_expr(
            expression="sqrt(a**2 + b**2)",
            channels={"a": head_accel_x, "b": head_accel_z},
            name="resultant_xz",
            unit="g",
        )
        assert result.name == "resultant_xz"
        assert result.unit == "g"
        assert result.peak > 0
        assert len(result.data) == len(head_accel_x.data)

    def test_constant_expression(self, head_accel_x):
        result = math_expr(
            expression="a * 0 + 42.0",
            channels={"a": head_accel_x},
            name="constant",
        )
        assert np.allclose(result.data, 42.0)

    def test_invalid_expression(self, head_accel_x):
        with pytest.raises(ValueError, match="Error evaluating"):
            math_expr(
                expression="invalid_func(a)",
                channels={"a": head_accel_x},
            )

    def test_forbidden_expression(self, head_accel_x):
        with pytest.raises(ValueError, match="Forbidden"):
            math_expr(
                expression="__import__('os')",
                channels={"a": head_accel_x},
            )


class TestResultant:
    def test_from_channels(self, head_accel_x, head_accel_y, head_accel_z):
        result = resultant_from_channels(head_accel_x, head_accel_y, head_accel_z)
        assert result.code.direction == "R"
        # Resultant >= any component
        assert result.peak >= head_accel_x.peak
        assert result.peak >= head_accel_y.peak

    def test_from_two_channels(self, head_accel_x, head_accel_z):
        result = resultant_from_channels(head_accel_x, head_accel_z)
        assert result.peak > 0

    def test_single_channel_raises(self):
        with pytest.raises(ValueError, match="At least one"):
            resultant_from_channels()


class TestTrimResample:
    def test_trim(self, head_accel_x):
        trimmed = trim(head_accel_x, t_start=0.0, t_end=0.05)
        assert trimmed.time[0] >= 0.0
        assert trimmed.time[-1] <= 0.05
        assert len(trimmed.data) < len(head_accel_x.data)

    def test_resample(self, head_accel_x):
        resampled = resample(head_accel_x, target_rate=5000.0)
        expected_samples = int(head_accel_x.duration * 5000.0)
        assert abs(len(resampled.data) - expected_samples) <= 2
        assert resampled.sample_rate == 5000.0
