// Copyright (c) 2026 Ourpad Network
// See LICENSE file in the project root for full license text.

#pragma once

#include <string>
#include <vector>
#include <memory>
#include <atomic>
#include <cstdint>
#include "mixer/Types.hpp"

namespace mixer {

/// An audio bus that accumulates contributions from multiple sources.
///
/// Buses form the mixing topology:
///   Channels → subgroups → master
///   Channels → aux sends → aux buses (monitor mixes)
///   Aux buses → FxReturn buses → subgroup or master
class MixerBus {
public:
    MixerBus(int64_t id, MixerBusType type, const std::string& name, int channels = 2);
    ~MixerBus() = default;

    /// Bus identity
    int64_t id() const { return id_; }
    MixerBusType type() const { return type_; }
    const std::string& name() const { return name_; }
    void setName(const std::string& name) { name_ = name; }

    /// Channel count (1 = mono, 2 = stereo, N = multi-channel)
    int channelCount() const { return channelCount_; }

    /// --- Control surface (atomic for RT-safe writes) ---

    /// Master volume in dB (-inf to +12.0)
    float volume() const { return volume_.load(); }
    void setVolume(float db);

    /// Mute
    bool mute() const { return mute_.load(); }
    void setMute(bool mute);

    /// --- Audio buffers ---

    /// Allocate internal buffers. Must be called before processing.
    void allocateBuffers(size_t maxFrames);

    /// Get read/write pointer to internal buffer for a channel
    float* buffer(int channel) {
        if (channel >= 0 && channel < (int)buffers_.size())
            return buffers_[channel].data();
        return nullptr;
    }
    const float* buffer(int channel) const {
        if (channel >= 0 && channel < (int)buffers_.size())
            return buffers_[channel].data();
        return nullptr;
    }

    /// Accumulate (sum) audio from a source into this bus with gain.
    void accumulate(
        const float* const* source,
        uint32_t frames,
        float gain,
        int sourceChannels
    );

    /// Same as accumulate but for a single interleaved source buffer
    void accumulateMono(
        const float* source,
        uint32_t frames,
        float gain
    );

    /// Clear all bus buffers to zero (must be called at start of each cycle)
    void clear();

    /// Apply bus-level processing (volume, mute) to the internal mix.
    void process(uint32_t frames);

    /// VU meter values after processing
    float vuLeft() const { return vuLeft_.load(); }
    float vuRight() const { return vuRight_.load(); }

    /// Max frames this bus can handle
    size_t maxFrames() const { return maxFrames_; }

private:
    int64_t id_;
    MixerBusType type_;
    std::string name_;
    int channelCount_;

    std::atomic<float> volume_{0.0f};   // dB
    std::atomic<bool> mute_{false};

    // Internal accumulation buffers [channel][sample]
    std::vector<std::vector<float>> buffers_;

    // VU tracking
    std::atomic<float> vuLeft_{-96.0f};
    std::atomic<float> vuRight_{-96.0f};

    size_t maxFrames_ = 512;
};

} // namespace mixer
