#include <why.h>
#include <why-sensor.h>
#include <why-irq.h>
#include <why-messagequeue.h>
#include <why-time.h>
#include <why-watchdog.h>
#include <why-thread.h>
#include <why-file.h>
#include <why-mqtt.h>

#include <string>
#include <format>


struct sensor_data
{
    Why::TimeSpec timestamp;
    std::string_view sensorname;
    uint64_t value;
};

int main()
{
    Why::init();

    Why::RandomSensor s1(0, 100);
    Why::RandomSensor s2(100, 200);

    auto sensor_data_queue = Why::MessageQueue<sensor_data>::create();
    assert(sensor_data_queue);

    auto csv_file = Why::File::open("data.csv", Why::File::WriteOnly|Why::File::Append|Why::File::Create);
    assert(csv_file);
    auto mqtt = Why::MQTTPublisher::create("why-topic", "127.0.0.1");
    assert(mqtt);

    // consume data in dedicated thread
    auto sensor_data_consumer = Why::Thread::create(
        [&sensor_data_queue, &csv_file, &mqtt](){
            while (true) {
                auto sample = sensor_data_queue->get();
                assert(sample);
                auto [timestamp, sensorname, value] = *sample;

                // write to CSV
                std::string line = std::format("{};{};{}\n", timestamp.to_seconds(), sensorname, value);
                auto written = csv_file->write((const uint8_t*)line.c_str(), line.size());
                assert(written);

                // publish MQTT
                std::string json = std::format("{{\"timestamp\": {}, \"sensorname\": {}, \"value\": {} }}", 
                                               timestamp.to_seconds(), sensorname, value);
                auto ok = mqtt->publish(json);
                assert(ok);
            }
        });
    assert(sensor_data_consumer);

    // activate sensor interrupts
    {
        auto isr = [&sensor_data_queue, &s1, &s2](int irqnum){
            sensor_data data;
            if (irqnum == 7)
                data = {.timestamp=Why::now_monotonic(), .sensorname="s1", .value=s1.get_value()};
            else if (irqnum == 42)
                data = {.timestamp=Why::now_monotonic(), .sensorname="s2", .value=s2.get_value()};
            else
                assert(!"unexpected irq");
        
            auto ok = sensor_data_queue->put_noblock(data);
            assert(ok);
        };
        Why::IRQ::connect(7, isr);
        Why::IRQ::connect(42, isr);
    }

    // activate and feed watchdog
    const Why::TimeSpec watchdog_timeout(2, 0);
    Why::Watchdog::activate(watchdog_timeout);
    while (true) {
        Why::Watchdog::feed();
        Why::sleep(watchdog_timeout - Why::TimeSpec(0, 500'000'000));
    }

    return 0;
}
