#pragma once
#include "rapidjson/document.h"
#include "rapidjson/filereadstream.h"
#include <cstdio>
#include <string>      // Added: needed for std::string
#include <vector>      // Added: needed for std::vector
#include <cassert>     // Added: needed for assert

struct Note {
    std::string name;
    int midi;
    int duration_ticks;
    int duration_ms; // Duration of the note in milliseconds
    int ticks;
    int position_ms; // How many milliseconds into the song the note occurs
};

struct Instrument {
    std::string family;
    int number;
};

struct Track {
    std::string name;
    Instrument instrument;
    std::vector<Note> notes;
};

struct Header {
    std::string name;
    std::string artist;
    int ppq;
    float bpm;
};

struct Song {
    Header header;
    std::vector<Track> tracks;
};

Song parseSong(const rapidjson::Document& doc) {
    assert(doc.IsObject());

    Song song;

    if (doc.HasMember("header") && doc["header"].IsObject()) {
        const auto& h = doc["header"].GetObject();
        Header header;
        header.name = h.HasMember("name") && h["name"].IsString() ? h["name"].GetString() : "";
        header.artist = h.HasMember("artist") && h["artist"].IsString() ? h["artist"].GetString() : "";
        header.ppq = h["ppq"].GetInt();
        if (h.HasMember("tempos") && h["tempos"].IsArray()) {
            const auto& tempos = h["tempos"].GetArray();
            header.bpm = tempos[0]["bpm"].GetFloat();
        }
        song.header = header;
    }

    if (doc.HasMember("tracks") && doc["tracks"].IsArray()) {
        const auto& a = doc["tracks"].GetArray();
        for (auto& t : a) {
            Track track;
            track.name = t["name"].GetString();

            if (t.HasMember("instrument") && t["instrument"].IsObject()) {  // Fixed: added closing parenthesis
                const auto& i = t["instrument"].GetObject();
                Instrument instrument;
                instrument.family = i["family"].GetString();
                instrument.number = i["number"].GetInt();
                track.instrument = instrument;
            }  // Fixed: removed extra closing parenthesis

            if (t.HasMember("notes") && t["notes"].IsArray()) {
                const auto& notes = t["notes"].GetArray();
                for (auto& n : notes) {
                    Note note;
                    note.name = n["name"].GetString();
                    note.midi = n["midi"].GetInt();
                    note.duration_ticks = n["durationTicks"].GetInt();
                    note.duration_ms = n["duration"].GetFloat() * 1000;
                    note.ticks = n["ticks"].GetInt();
                    note.position_ms = n["time"].GetFloat() * 1000;
                    track.notes.push_back(note);
                }
            }

            song.tracks.push_back(track);
        }
    }

    return song;
}