//@version=5
indicator("FFT Top Components (Individual Curves)", overlay=false)

int n = input.int(128, title="Sample Size", minval=32, maxval=512)
int topComponents = input.int(6, title="Top Components", minval=1, maxval=20)

var float[] priceBuffer = array.new_float(n, 0.0)
var int bufferIndex = 0

if bar_index >= n
    array.set(priceBuffer, bufferIndex, close)
    bufferIndex := (bufferIndex + 1) % n

var float[] amplitudes = array.new_float(n, 0.0)
var float[] phases = array.new_float(n, 0.0)

if bar_index >= n
    for k = 0 to n - 1
        float re = 0.0
        float im = 0.0
        for t = 0 to n - 1
            float val = array.get(priceBuffer, (bufferIndex + t) % n)
            float angle = 2.0 * math.pi * k * t / n
            re += val * math.cos(angle)
            im -= val * math.sin(angle)
        float amp = math.sqrt(re * re + im * im) / n
        float phase = re != 0 ? math.atan(im / re) : 0
        array.set(amplitudes, k, amp)
        array.set(phases, k, phase)

var float[] sortableAmps = array.new_float(0)
var int[] sortableIndices = array.new_int(0)

if bar_index >= n
    array.clear(sortableAmps)
    array.clear(sortableIndices)
    for i = 0 to n - 1
        array.push(sortableAmps, array.get(amplitudes, i))
        array.push(sortableIndices, i)

    int arraySize = array.size(sortableAmps)
    for i = 0 to arraySize - 2
        for j = i + 1 to arraySize - 1
            if array.get(sortableAmps, j) > array.get(sortableAmps, i)
                float tempAmp = array.get(sortableAmps, i)
                int tempIdx = array.get(sortableIndices, i)
                array.set(sortableAmps, i, array.get(sortableAmps, j))
                array.set(sortableIndices, i, array.get(sortableIndices, j))
                array.set(sortableAmps, j, tempAmp)
                array.set(sortableIndices, j, tempIdx)

// Predefine component series
var float comp0 = na
var float comp1 = na
var float comp2 = na
var float comp3 = na
var float comp4 = na
var float comp5 = na

if bar_index >= n
    int maxComp = math.min(topComponents - 1, array.size(sortableIndices) - 1)
    
    // Get the current time index within the buffer
    float currentTimeIndex = float(bufferIndex)
    
    for i = 0 to maxComp
        int idx = array.get(sortableIndices, i)
        float amp = array.get(amplitudes, idx)
        float phase = array.get(phases, idx)
        
        // Reconstruct component using cosine with corrected phase
        float angle = 2.0 * math.pi * idx * (currentTimeIndex - 1) / n
        float component = amp * math.cos(angle + phase)
        
        if i == 0
            comp0 := component
        if i == 1
            comp1 := component
        if i == 2
            comp2 := component
        if i == 3
            comp3 := component
        if i == 4
            comp4 := component
        if i == 5
            comp5 := component

// Plots (global scope)
//plot(comp0, title="Component 0", color=color.blue)
plot(comp1, title="Component 1", color=color.green)
plot(comp2, title="Component 2", color=color.red)
plot(comp3, title="Component 3", color=color.orange)
plot(comp4, title="Component 4", color=color.purple)
plot(comp5, title="Component 5", color=color.aqua)

