#include "sensor.h"
#include "switch.h"
#include "fsm.h"

#include <can-jf0815.h>

#include <why-timer.h>
#include <why-irq.h>
#include <why-time.h>
#include <why-thread.h>

#include <print>
#include <cstring>


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

    Sensor sensor("/tmp/plant/temperature");
    Switch cooling_switch("/tmp/plant/cooling");
    Switch soft_alarm("/tmp/plant/soft-alarm");
    Switch hard_alarm("/tmp/plant/hard-alarm");
    std::string can_iface("my-can");
    const int can_id = 37;
    CAN_JF0815 can_controller(can_iface);
    Why::MessageQueue<FSM::State> state_change_queue;
    Why::Semaphore timer_tick_sem(0);
    Why::Timer interval_timer([&timer_tick_sem](){
        timer_tick_sem.give();
    });
    Why::Semaphore sensor_burning_sem(0);
    Why::Semaphore operator_button_sem(0);

    const long LOW_TEMP = 20;
    const long HIGH_TEMP = 500'000;
    const long SOFT_ALARM_TEMP = 1'000'000;
    const int SENSOR_BURNING_IRQ = 7;
    const int OPERATOR_BUTTON_IRQ = 42;

    std::println("* Thermostat lo: {}", LOW_TEMP);
    std::println("* Thermostat hi: {}", HIGH_TEMP);
    std::println("* Soft critical: {}", SOFT_ALARM_TEMP);
    std::println("* Cooling switch: {}", cooling_switch.path());
    std::println("* Soft alarm: {}", soft_alarm.path());
    std::println("* Hard alarm: {}", hard_alarm.path());
    std::println("* Sensor burning IRQ: {}", SENSOR_BURNING_IRQ);
    std::println("* Operator button IRQ: {}", OPERATOR_BUTTON_IRQ);

    FSM fsm(
        hard_alarm,
        SOFT_ALARM_TEMP, soft_alarm,
        state_change_queue,
        sensor, cooling_switch,
        LOW_TEMP, HIGH_TEMP
    );

    fsm.start();

    Why::Thread can_thread(
        [&can_controller, &state_change_queue](){
            while (true) {
                FSM::State state =
                    state_change_queue.get();

                uint32_t notify_state;
                switch (state) {
                    case FSM::State::INIT:
                        notify_state = 0;
                        break;
                    case FSM::State::RUNNING:
                        notify_state = 1;
                        break;
                    case FSM::State::OVERTEMP:
                        notify_state = 2;
                        break;
                    case FSM::State::SENSORBURNING:
                        notify_state = 3;
                        break;
                }

                CANFrame frame;
                frame.id = can_id;
                frame.dlc = sizeof(notify_state);
                memcpy(frame.data, &notify_state, sizeof(notify_state));

                can_controller.xmit(frame);
            }
        }
    );

    jjj one thread;

    Why::Thread timer_tick_thread(
        [&fsm, &timer_tick_sem](){
            while (true) {
                timer_tick_sem.take();
                fsm.timer_tick();
            }
        });
    interval_timer.start(
        Why::TimeSpec(0,1), Why::TimeSpec(0, 1'000'000));

    Why::Thread sensor_burning_thread(
        [&fsm, &sensor_burning_sem](){
            while (true) {
                sensor_burning_sem.take();
                fsm.sensor_burning();
            }
        });
    Why::IRQ::connect(
        SENSOR_BURNING_IRQ,
        [&sensor_burning_sem](int irqnum) {
            sensor_burning_sem.give();
        }
    );

    Why::Thread operator_button_thread(
        [&fsm, &operator_button_sem](){
            while (true) {
                operator_button_sem.take();
                fsm.operator_button_pressed();
            }
        });
    Why::IRQ::connect(
        OPERATOR_BUTTON_IRQ,
        [&operator_button_sem](int irqnum) {
            operator_button_sem.give();
        }
    );

    Why::pause();
    return 0;
}
