// SPDX-License-Identifier: Unlicense

#include "wavreader.h"

#include <stdint.h>
#include <string.h>

FILE* fopen_wav_file_seek_to_audio_data(const char* wav_filepath, unsigned int* sample_rate, unsigned int* data_bytes)
{
  FILE* file = fopen(wav_filepath, "rb");
  if (file == NULL)
  {
    fprintf(stderr, "File could not be opened.\n");
    fprintf(stderr, "Usage: hexfin-example <path/to/32-bit-float-mono.wav>\n");
    return NULL;
  }

  {
#pragma pack(push)
#pragma pack(1)
    struct WAV_Header {
      // RIFF Header
      char riff_header[4]; // Contains "RIFF"
      uint32_t wav_size; // Size of the wav portion of the file, which follows the first 8 bytes. File size - 8
      char wave_header[4]; // Contains "WAVE"

      // Format Header
      char fmt_header[4]; // Contains "fmt " (includes trailing space)
      uint32_t fmt_chunk_size; // Should be 16 for PCM
      uint16_t audio_format; // Should be 1 for PCM. 3 for IEEE Float
      uint16_t num_channels;
      uint32_t sample_rate;
      uint32_t byte_rate; // Number of bytes per second. sample_rate * num_channels * Bytes Per Sample
      uint16_t sample_alignment; // num_channels * Bytes Per Sample
      uint16_t bit_depth; // Number of bits per sample
    };
#pragma pack(pop)

    struct WAV_Header wav_header;

    const size_t bytesRead = fread(&wav_header, 1, sizeof(struct WAV_Header), file);

    if (bytesRead != sizeof(struct WAV_Header))
    {
      fprintf(stderr, "Error: Incomplete WAV header. The header is too short.\n");
      fclose(file);
      return NULL;
    }

    if (strncmp(wav_header.riff_header, "RIFF", 4) != 0
      || strncmp(wav_header.wave_header, "WAVE", 4) != 0
      || strncmp(wav_header.fmt_header, "fmt ", 4) != 0)
    {
      fprintf(stderr, "Error: Invalid file format. The file is not a valid WAV file.\n");
      fclose(file);
      return NULL;
    }

    if (wav_header.num_channels != 1)
    {
      fprintf(stderr, "Warning: Expected mono audio.\n");
    }

    if (wav_header.audio_format != 3 || wav_header.bit_depth != 32)
    {
      fprintf(stderr, "Warning: Expected 32-bit float audio.\n");
    }

    *sample_rate = wav_header.sample_rate;
  }
  {
#pragma pack(push)
#pragma pack(1)
    struct WAV_Subchunk2
    {
      // Data
      char data_header[4]; // Contains "data"
      uint32_t data_bytes; // Number of bytes in data. Number of samples * num_channels * sample byte size
    };
#pragma pack(pop)

    struct WAV_Subchunk2 wav_subchunk2;
    for (;;)
    {
      fread(&wav_subchunk2, 1, sizeof(struct WAV_Subchunk2), file);
      if (strncmp(wav_subchunk2.data_header, "data", 4) == 0)
        break;
      else
      {
        fprintf(stderr, "Warning: Expected 'data' subchunk after header, but found a different subchunk. Skipping...\n");
        fseek(file, wav_subchunk2.data_bytes, SEEK_CUR);
      }
    }

    *data_bytes = wav_subchunk2.data_bytes;
  }

  return file;
}
