#include "API.h"

#include <utility>
#include "note.h"
#include "pybind11/pybind11.h"

namespace py = pybind11;
namespace mg = midi_generator;
using namespace py::literals;

template<typename T>
py::list to_python_list(std::list<T> std_list) {
    typename std::list<T>::iterator iter;
    py::list python_list;
    for (iter = std_list.begin(); iter != std_list.end(); ++iter) {
        python_list.append(*iter);
    }
    return python_list;
}

std::list<mg::Note> mg::generate() {
    try {
        pybind11::module_ commands = pybind11::module_::import("midi_generator.commands");
        py::object result = commands.attr("generate")();
        std::list<mg::Note> notes;
        for(const auto& obj: result)
            notes.emplace_back(
                    obj.attr("pitch").cast<int>(),
                    obj.attr("velocity").cast<int>(),
                    obj.attr("start").cast<double>(),
                    obj.attr("end").cast<double>()
                    );

        return notes;
    } catch (py::error_already_set &error) {
        error.discard_as_unraisable(__func__ );
        return {};
    }
}

std::list<mg::Note> mg::mutate(std::list<mg::Note> notes) {
    try {
        pybind11::module_ commands = pybind11::module_::import("midi_generator.commands");
        py::object result = commands.attr("mutate")(to_python_list(std::move(notes)));

        std::list<mg::Note> mutant;
        for(const auto& obj: result)
            mutant.emplace_back(
                    obj.attr("pitch").cast<int>(),
                    obj.attr("velocity").cast<int>(),
                    obj.attr("start").cast<double>(),
                    obj.attr("end").cast<double>()
            );
        return mutant;
    } catch (py::error_already_set &error) {
        error.discard_as_unraisable(__func__ );
        return {};
    }
}

std::list<mg::Note> continue_sequence() {
    std::list<mg::Note> notes;
    return notes;
}

std::list<mg::Note> combine() {
    std::list<mg::Note> notes;
    return notes;
}

void mg::save_file(std::string filename, std::list<mg::Note> notes) {
}