#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <chrono>
#include <signal.h>
#include <atomic>
#include <iomanip>

#include <k230_audio.h>
#include <k230_wave.h>

static void record_audio_pdm(const std::string& base_filename, int duration, int num_channels) {
    const int CHUNK = 44100 / 25;  // Audio buffer size
    AudioFormat format = paInt16;   // Sample precision
    const int RATE = 44100;         // Sample rate
    int pdm_chn_cnt = num_channels / 2;

    /*
    * Initialize PDM audio IO
    *
    * Configure GPIO pin functions for PDM audio acquisition on the Lushanpai development board:
    * - Map PDM clock line and data lines to specified physical pins
    * - Set pin directions (input/output mode)
    *
    * Specific pin assignments:
    * - Pin 26: PDM clock line (PDM_CLK)  → Output mode
    * - Pin 27: PDM data 0 line (PDM_IN0) → Input mode
    * - Pin 35: PDM data 1 line (PDM_IN1) → Input mode
    * - Pin 36: PDM data 2 line (PDM_IN2) → Input mode
    * - Pin 34: PDM data 3 line (PDM_IN3) → Input mode
    */
    if (0 != ArduinoAudio::pdm_audio_pin_config(26, 27, 35, 36, 34)){
        printf("pdm_audio_pin_config failed\n");
        return ;
    }

    try {
        ArduinoAudio audio;

        // Open audio input stream
        AudioStream* stream = audio.open(
            RATE,
            num_channels,
            format,
            true,   // Input stream
            false,  // Not output stream
            1,      // PDM device index
            -1,     // Do not use output device
            false,  // Enable hardware codec
            CHUNK,  // Frames per buffer
            false   // Start stream immediately
        );

        if (!stream || !stream->is_input()) {
            throw std::runtime_error("Failed to create input audio stream");
        }

        // Start the stream
        stream->start_stream();

        // Initialize audio frame storage for each channel
        std::vector<std::vector<uint8_t>> channel_frames(pdm_chn_cnt);

        // Calculate total number of frames
        int total_frames = static_cast<int>(RATE / CHUNK * duration);

        std::cout << "Starting recording of " << pdm_chn_cnt << " groups of "
                  << num_channels << " channels PDM audio, duration " << duration << " seconds..." << std::endl;

        // Collect audio data
        for (int i = 0; i < total_frames; ++i) {
            for (int ch = 0; ch < pdm_chn_cnt; ++ch) {
                std::vector<uint8_t> data;
                if (stream->read(data, ch, true) == 0) {
                    // Append read data to corresponding channel buffer
                    channel_frames[ch].insert(channel_frames[ch].end(),
                                            data.begin(), data.end());
                }
            }

            // Print progress every 25 frames
            if (i % 25 == 0) {
                float progress = (static_cast<float>(i) / total_frames) * 100;
                std::cout << "Recording progress: " << std::fixed << std::setprecision(2) << progress << "%" << std::endl;
            }
        }

        stream->stop_stream();

        std::cout << "Recording progress: " << std::fixed << std::setprecision(2) << 100 << "%" << std::endl;

        // Save each channel's data to WAV file
        for (int ch = 0; ch < pdm_chn_cnt; ++ch) {
            std::string filename = base_filename + "_ch" + std::to_string(ch) + ".wav";

            try {
                WaveWrite wf(filename);
                wf.set_channels(2);  // Save stereo in each file
                wf.set_sampwidth(audio.get_sample_size(format));  // Set sample precision
                wf.set_framerate(RATE);  // Set sample rate

                // Convert uint8_t vector to char vector
                std::vector<char> char_data(channel_frames[ch].begin(),
                                         channel_frames[ch].end());
                wf.write_frames(char_data);

                std::cout << "Saved channels " << ch*2 << "," << ch*2+1
                          << " to " << filename << std::endl;
            } catch (const WaveError& e) {
                std::cerr << "Failed to save WAV file: " << e.what() << std::endl;
            }
        }

        // Clean up resources
        audio.close(stream);

    } catch (const std::exception& e) {
        std::cerr << "Error occurred: " << e.what() << std::endl;
    }

    std::cout << "Recording completed, resources released" << std::endl;
}


void setup()
{
    record_audio_pdm("/data/pdm", 15, 8);
}

void loop()
{

}