"""Power and efficiency calculations from simulation data."""

import numpy as np

# np.trapz was renamed to np.trapezoid in numpy 2.0
_trapz = getattr(np, "trapezoid", getattr(np, "trapz", None))


def compute_instantaneous_power(voltage: np.ndarray, current: np.ndarray) -> np.ndarray:
    """Element-wise power: P(t) = V(t) * I(t).

    Args:
        voltage: Voltage waveform array
        current: Current waveform array

    Returns:
        Instantaneous power array (same length as inputs)
    """
    return np.real(voltage) * np.real(current)


def compute_average_power(time: np.ndarray, voltage: np.ndarray, current: np.ndarray) -> float:
    """Time-averaged power: P_avg = (1/T) * integral(V*I dt).

    Uses trapezoidal integration over the full time span.

    Args:
        time: Time array in seconds
        voltage: Voltage waveform array
        current: Current waveform array

    Returns:
        Average power in watts
    """
    t = np.real(time)
    duration = t[-1] - t[0]

    if len(t) < 2 or duration <= 0:
        return 0.0

    p_inst = np.real(voltage) * np.real(current)
    return float(_trapz(p_inst, t) / duration)


def compute_efficiency(
    time: np.ndarray,
    input_voltage: np.ndarray,
    input_current: np.ndarray,
    output_voltage: np.ndarray,
    output_current: np.ndarray,
) -> dict:
    """Compute power conversion efficiency.

    Args:
        time: Time array in seconds
        input_voltage: Input voltage waveform
        input_current: Input current waveform
        output_voltage: Output voltage waveform
        output_current: Output current waveform

    Returns:
        Dict with efficiency_percent, input_power_watts,
        output_power_watts, power_dissipated_watts
    """
    p_in = compute_average_power(time, input_voltage, input_current)
    p_out = compute_average_power(time, output_voltage, output_current)
    p_dissipated = p_in - p_out

    if abs(p_in) < 1e-15:
        efficiency = 0.0
    else:
        efficiency = (p_out / p_in) * 100.0

    return {
        "efficiency_percent": efficiency,
        "input_power_watts": p_in,
        "output_power_watts": p_out,
        "power_dissipated_watts": p_dissipated,
    }


def compute_power_spectrum(
    time: np.ndarray,
    voltage: np.ndarray,
    current: np.ndarray,
    max_harmonics: int = 20,
) -> dict:
    """FFT of instantaneous power to identify ripple frequencies.

    Args:
        time: Time array in seconds
        voltage: Voltage waveform array
        current: Current waveform array
        max_harmonics: Maximum number of frequency bins to return

    Returns:
        Dict with frequencies, power_magnitudes, dominant_freq, dc_power
    """
    t = np.real(time)

    if len(t) < 2:
        return {
            "frequencies": [],
            "power_magnitudes": [],
            "dominant_freq": 0.0,
            "dc_power": 0.0,
        }

    dt = (t[-1] - t[0]) / (len(t) - 1)
    if dt <= 0:
        return {
            "frequencies": [],
            "power_magnitudes": [],
            "dominant_freq": 0.0,
            "dc_power": float(np.mean(np.real(voltage) * np.real(current))),
        }

    p_inst = np.real(voltage) * np.real(current)
    n = len(p_inst)

    spectrum = np.fft.rfft(p_inst)
    freqs = np.fft.rfftfreq(n, d=dt)
    magnitudes = np.abs(spectrum) * 2.0 / n
    magnitudes[0] /= 2.0  # DC component correction

    dc_power = float(magnitudes[0])

    # Dominant AC frequency (largest non-DC bin)
    if len(magnitudes) > 1:
        dominant_idx = int(np.argmax(magnitudes[1:])) + 1
        dominant_freq = float(freqs[dominant_idx])
    else:
        dominant_freq = 0.0

    # Trim to requested harmonics (plus DC)
    limit = min(max_harmonics + 1, len(freqs))
    freqs = freqs[:limit]
    magnitudes = magnitudes[:limit]

    return {
        "frequencies": freqs.tolist(),
        "power_magnitudes": magnitudes.tolist(),
        "dominant_freq": dominant_freq,
        "dc_power": dc_power,
    }


def compute_power_metrics(time: np.ndarray, voltage: np.ndarray, current: np.ndarray) -> dict:
    """Comprehensive power report for a voltage/current pair.

    Power factor here is defined as the ratio of real (average) power
    to apparent power (Vrms * Irms).

    Args:
        time: Time array in seconds
        voltage: Voltage waveform array
        current: Current waveform array

    Returns:
        Dict with avg_power, rms_power, peak_power, min_power, power_factor
    """
    v = np.real(voltage)
    i = np.real(current)
    p_inst = v * i

    if len(p_inst) == 0:
        return {
            "avg_power": 0.0,
            "rms_power": 0.0,
            "peak_power": 0.0,
            "min_power": 0.0,
            "power_factor": 0.0,
        }

    avg_power = compute_average_power(time, voltage, current)
    rms_power = float(np.sqrt(np.mean(p_inst**2)))
    peak_power = float(np.max(p_inst))
    min_power = float(np.min(p_inst))

    # Power factor = avg power / apparent power (Vrms * Irms)
    v_rms = float(np.sqrt(np.mean(v**2)))
    i_rms = float(np.sqrt(np.mean(i**2)))
    apparent = v_rms * i_rms

    if apparent < 1e-15:
        power_factor = 0.0
    else:
        power_factor = avg_power / apparent

    return {
        "avg_power": avg_power,
        "rms_power": rms_power,
        "peak_power": peak_power,
        "min_power": min_power,
        "power_factor": power_factor,
    }
