#include <stdio.h>
#include "audio.h"
#include <stdio.h>
#include <inttypes.h>
#include <sdkconfig.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "bsp/esp-bsp.h"

/* Buffer for reading/writing to I2S driver. Same length as SPIFFS buffer and I2S buffer, for optimal read/write performance.
   External SPI Flash -> SPIFFS buffer -> App buffer (RAM) -> I2S buffer (DMA) -> I2S peripheral.
*/
#define BUFFER_SIZE     (1024)
#define DEFAULT_VOLUME  (50)

/* Globals */
static const char *TAG = "audio";
TaskHandle_t audio_task_handle;


// Very simple WAV header, ignores most fields
typedef struct __attribute__((packed))
{
    uint8_t ignore_0[22];
    uint16_t num_channels;
    uint32_t sample_rate;
    uint8_t ignore_1[6];
    uint16_t bits_per_sample;
    uint8_t ignore_2[4];
    uint32_t data_size;
    uint8_t data[];
} dumb_wav_header_t;

typedef struct {
    FILE *f;
    uint32_t data_offset;
    uint32_t data_size;
} wav_ctx_t;
#define AUDIO_CHUNK_SIZE 4096

bool wav_open(wav_ctx_t *ctx, const char *path)
{
    ctx->f = fopen(path, "rb");
    if (!ctx->f) return false;

    /* Skip RIFF header */
    fseek(ctx->f, 12, SEEK_SET);

    uint32_t chunk_id, chunk_size;

    while (fread(&chunk_id, 4, 1, ctx->f))
    {
        fread(&chunk_size, 4, 1, ctx->f);

        if (chunk_id == 0x61746164) { // "data"
            ctx->data_offset = ftell(ctx->f);
            ctx->data_size = chunk_size;
            return true;
        }

        fseek(ctx->f, chunk_size, SEEK_CUR);
    }

    fclose(ctx->f);
    return false;
}
void rewind_wav(wav_ctx_t *ctx)
{
    fseek(ctx->f, ctx->data_offset, SEEK_SET);
}
#define AUDIO_CHUNK_SIZE 4096
static void audio_task(void *arg)
{
    ESP_LOGI(TAG,"Audio task");

    esp_codec_dev_handle_t spk_codec_dev = bsp_audio_codec_speaker_init();
    assert(spk_codec_dev);

    esp_codec_dev_set_out_vol(spk_codec_dev, DEFAULT_VOLUME);
    esp_codec_dev_set_out_mute(spk_codec_dev, false);   // 🔑 CRITIQUE

    const char *play_filename = "/littlefs/sounds/mixkit-clear-announce-tones-2861.wav";

    uint8_t *wav_bytes = malloc(BUFFER_SIZE);
    assert(wav_bytes != NULL);

    for (;;)
    {
        /* ⏸️ Attend PLAY */
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
        bool stop_requested = false;

        while (!stop_requested) {
            ESP_LOGI(TAG,"On joue !");

            FILE *play_file = fopen(play_filename, "rb");
            if (!play_file) {
                ESP_LOGE(TAG,"File not found");
                break;
            }

            dumb_wav_header_t wav_header;
            if (fread(&wav_header, 1, sizeof(wav_header), play_file) != sizeof(wav_header)) {
                ESP_LOGE(TAG,"Header read failed");
                fclose(play_file);
                break;
            }

            esp_codec_dev_sample_info_t fs = {
                .sample_rate = wav_header.sample_rate,
                .channel = wav_header.num_channels,
                .bits_per_sample = wav_header.bits_per_sample,
            };

            ESP_ERROR_CHECK(esp_codec_dev_open(spk_codec_dev, &fs));

            uint32_t bytes_sent = 0;
            while (bytes_sent < wav_header.data_size) {
                size_t bytes_read = fread(wav_bytes, 1, BUFFER_SIZE, play_file);
                if (bytes_read == 0) break;

                esp_codec_dev_write(spk_codec_dev, wav_bytes, bytes_read);
                bytes_sent += bytes_read;

                vTaskDelay(1);   // watchdog + scheduler
            }

            esp_codec_dev_close(spk_codec_dev);
            fclose(play_file);

            ESP_LOGI(TAG,"Fin du fichier");

            if (ulTaskNotifyTake(pdTRUE, 0) > 0) {
                stop_requested = true;
            }
        }
    }
    free(wav_bytes);
}
static void audio_task__(void *arg)
{
    ESP_LOGE(TAG,"Audio task");
    esp_codec_dev_handle_t spk_codec_dev = bsp_audio_codec_speaker_init();
    assert(spk_codec_dev);
    esp_codec_dev_set_out_vol(spk_codec_dev, DEFAULT_VOLUME);

    /* Pointer to a file that is going to be played */
    const char music_filename[] = "/littlefs/sounds/mixkit-clear-announce-tones-2861.wav";
    const char *play_filename = music_filename;

    int16_t *wav_bytes = malloc(BUFFER_SIZE);
    assert(wav_bytes != NULL);

    bool stop_requested = false;

    while (!stop_requested){
                ESP_LOGE(TAG,"On joue !");
                /* Open WAV file */
                ESP_LOGI(TAG, "Playing file %s", play_filename);
                FILE *play_file = fopen(play_filename, "rb");
                if (play_file == NULL) {
                    ESP_LOGW(TAG, "%s file does not exist!", play_filename);
                    break;
                }

                /* Read WAV header file */
                dumb_wav_header_t wav_header;
                if (fread((void *)&wav_header, 1, sizeof(wav_header), play_file) != sizeof(wav_header)) {
                    ESP_LOGW(TAG, "Error in reading file");
                    break;
                }
                //ESP_LOGI(TAG, "Number of channels: %" PRIu16 "", wav_header.num_channels);
                //ESP_LOGI(TAG, "Bits per sample: %" PRIu16 "", wav_header.bits_per_sample);
                //ESP_LOGI(TAG, "Sample rate: %" PRIu32 "", wav_header.sample_rate);
                //ESP_LOGI(TAG, "Data size: %" PRIu32 "", wav_header.data_size);

                esp_codec_dev_sample_info_t fs = {
                    .sample_rate = wav_header.sample_rate,
                    .channel = wav_header.num_channels,
                    .bits_per_sample = wav_header.bits_per_sample,
                };
                esp_codec_dev_open(spk_codec_dev, &fs);

                uint32_t bytes_send_to_i2s = 0;
                while (bytes_send_to_i2s < wav_header.data_size) {
                    /* Get data from SPIFFS and send it to codec */
                    size_t bytes_read_from_spiffs = fread(wav_bytes, 1, BUFFER_SIZE, play_file);
                    esp_codec_dev_write(spk_codec_dev, wav_bytes, bytes_read_from_spiffs);
                    bytes_send_to_i2s += bytes_read_from_spiffs;

                    /* ⭐ LIGNE CRITIQUE ⭐ */
                    vTaskDelay(1);   // laisse respirer IDLE + watchdog
                }
                ESP_LOGE(TAG,"On a fini le fichier");

                fclose(play_file);
                esp_codec_dev_close(spk_codec_dev);
                if(ulTaskNotifyTake(pdTRUE, 0)>0){
                    stop_requested=true;
                    break;
                };

        }
        free(wav_bytes);
        vTaskSuspend(NULL);
    }

void playSound(void)
{
    if(audio_task_handle==NULL){
        BaseType_t ret = xTaskCreate(audio_task, "audio_task", 4096, NULL, 6, &audio_task_handle);
        assert(ret == pdPASS);
    }
    xTaskNotifyGive(audio_task_handle);
}
void stopSound(void){
    if (audio_task_handle) {
        xTaskNotifyGive(audio_task_handle);
    }
}


