#include "acoustic_analyzer/core/audio_buffer.h"
#include <algorithm>
#include <cstring>

namespace acoustic {

AudioBuffer::AudioBuffer(std::size_t capacity_samples, std::size_t num_channels)
    : capacity_frames_(capacity_samples > 0 ? capacity_samples : 1),
      num_channels_(num_channels),
      buffer_(capacity_frames_ * num_channels),
      head_(0),
      tail_(0),
      size_(0) {
}

std::size_t AudioBuffer::Push(const std::vector<float>& samples) {
    if (num_channels_ == 0) return 0;
    std::size_t total_frames = samples.size() / num_channels_;
    for (std::size_t f = 0; f < total_frames; ++f) {
        for (std::size_t ch = 0; ch < num_channels_; ++ch) {
            std::size_t idx = head_ * num_channels_ + ch;
            buffer_[idx] = samples[f * num_channels_ + ch];
        }
        head_ = (head_ + 1) % capacity_frames_;
        if (size_ < capacity_frames_) {
            ++size_;
        } else {
            tail_ = (tail_ + 1) % capacity_frames_;
        }
    }
    return total_frames;
}

std::vector<float> AudioBuffer::Pop(std::size_t num_frames) {
    std::size_t frames_to_read = std::min(num_frames, size_);
    std::vector<float> result(frames_to_read * num_channels_);
    for (std::size_t f = 0; f < frames_to_read; ++f) {
        for (std::size_t ch = 0; ch < num_channels_; ++ch) {
            result[f * num_channels_ + ch] = buffer_[tail_ * num_channels_ + ch];
        }
        tail_ = (tail_ + 1) % capacity_frames_;
    }
    size_ -= frames_to_read;
    return result;
}

std::vector<float> AudioBuffer::Get(std::size_t offset, std::size_t num_frames) const {
    if (offset >= size_) return {};
    std::size_t frames_to_read = std::min(num_frames, size_ - offset);
    std::vector<float> result(frames_to_read * num_channels_);
    std::size_t start = (tail_ + offset) % capacity_frames_;
    for (std::size_t f = 0; f < frames_to_read; ++f) {
        std::size_t pos = (start + f) % capacity_frames_;
        for (std::size_t ch = 0; ch < num_channels_; ++ch) {
            result[f * num_channels_ + ch] = buffer_[pos * num_channels_ + ch];
        }
    }
    return result;
}

std::size_t AudioBuffer::Size() const noexcept {
    return size_;
}

std::size_t AudioBuffer::Capacity() const noexcept {
    return capacity_frames_;
}

void AudioBuffer::Clear() {
    head_ = 0;
    tail_ = 0;
    size_ = 0;
    std::fill(buffer_.begin(), buffer_.end(), 0.0f);
}

std::size_t AudioBuffer::NumChannels() const noexcept {
    return num_channels_;
}

} // namespace acoustic
