//go:build cufft && windows

package gpudemod

import (
	"errors"
	"math"
	"unsafe"

	"sdr-visual-suite/internal/dsp"
)

func (r *BatchRunner) shiftFilterDecimateBatchImpl(iq []complex64) ([][]complex64, []int, error) {
	outs := make([][]complex64, len(r.slots))
	rates := make([]int, len(r.slots))
	for i := range r.slots {
		if !r.slots[i].active {
			continue
		}
		out, rate, err := r.shiftFilterDecimateSlot(iq, r.slots[i].job, nil)
		if err != nil {
			return nil, nil, err
		}
		r.slots[i].out = out
		r.slots[i].rate = rate
		outs[i] = out
		rates[i] = rate
	}
	return outs, rates, nil
}

func (r *BatchRunner) shiftFilterDecimateSlot(iq []complex64, job ExtractJob, stream streamHandle) ([]complex64, int, error) {
	e := r.eng
	if e == nil || !e.cudaReady {
		return nil, 0, ErrUnavailable
	}
	if len(iq) == 0 {
		return nil, 0, nil
	}
	cutoff := job.BW / 2
	if cutoff < 200 {
		cutoff = 200
	}
	base64 := dsp.LowpassFIR(cutoff, e.sampleRate, 101)
	taps := make([]float32, len(base64))
	for i, v := range base64 {
		taps[i] = float32(v)
	}
	if len(taps) == 0 {
		return nil, 0, errors.New("no FIR taps configured")
	}
	e.SetFIR(taps)
	if stream == nil {
		if bridgeDeviceSync() != 0 {
			return nil, 0, errors.New("cudaDeviceSynchronize failed")
		}
	}
	decim := int(math.Round(float64(e.sampleRate) / float64(job.OutRate)))
	if decim < 1 {
		decim = 1
	}
	n := len(iq)
	nOut := n / decim
	if nOut <= 0 {
		return nil, 0, errors.New("not enough output samples after decimation")
	}
	bytesIn := uintptr(n) * unsafe.Sizeof(complex64(0))
	if bridgeMemcpyH2D(unsafe.Pointer(e.dIQIn), unsafe.Pointer(&iq[0]), bytesIn) != 0 {
		return nil, 0, errors.New("cudaMemcpy H2D failed")
	}
	phaseInc := -2.0 * math.Pi * job.OffsetHz / float64(e.sampleRate)
	phaseStart := e.phase
	if bridgeLaunchFreqShiftStream(e.dIQIn, e.dShifted, n, phaseInc, phaseStart, stream) != 0 {
		return nil, 0, errors.New("gpu freq shift failed")
	}
	if bridgeLaunchFIRStream(e.dShifted, e.dFiltered, n, len(taps), stream) != 0 {
		return nil, 0, errors.New("gpu FIR failed")
	}
	if bridgeLaunchDecimateStream(e.dFiltered, e.dDecimated, nOut, decim, stream) != 0 {
		return nil, 0, errors.New("gpu decimate failed")
	}
	if stream != nil {
		if bridgeStreamSync(stream) != 0 {
			return nil, 0, errors.New("cuda stream sync failed")
		}
	} else {
		if bridgeDeviceSync() != 0 {
			return nil, 0, errors.New("cudaDeviceSynchronize failed")
		}
	}
	out := make([]complex64, nOut)
	outBytes := uintptr(nOut) * unsafe.Sizeof(complex64(0))
	if bridgeMemcpyD2H(unsafe.Pointer(&out[0]), unsafe.Pointer(e.dDecimated), outBytes) != 0 {
		return nil, 0, errors.New("cudaMemcpy D2H failed")
	}
	e.phase = phaseStart + phaseInc*float64(n)
	return out, e.sampleRate / decim, nil
}
