#include "mqtt_message_router.h"

#include <nlohmann/json.hpp>

#include <array>
#include <algorithm>
#include <iostream>

namespace mqtt {
namespace {

bool is_audio_message(int type){
    constexpr std::array<int, 4> types{{5, 2001, 2017, 2027}};
    return std::find(types.begin(), types.end(), type) != types.end();
}

bool is_device_control_message(int type){
    constexpr std::array<int, 20> types{{
        2, 3, 4, 6, 7,
        2002, 2003, 2004, 2006, 2007, 2008, 2009,
        2011, 2012, 2013, 2016, 2025, 2026, 2028, 2104
    }};
    return std::find(types.begin(), types.end(), type) != types.end();
}

} // namespace

void MessageRouter::set_device_control_handler(Handler handler){
    std::lock_guard<std::mutex> lock(mutex_);
    device_control_handler_ = std::move(handler);
}

void MessageRouter::route(const std::string &topic,
                          const std::string &payload) const{
    IncomingMessage incoming{topic, payload, -1};
    try {
        const nlohmann::json root = nlohmann::json::parse(payload);
        if(root.contains("head") && root["head"].is_object() &&
           root["head"].contains("message_type") &&
           root["head"]["message_type"].is_number_integer()){
            incoming.message_type = root["head"]["message_type"].get<int>();
        }else if(root.contains("message_type") &&
                 root["message_type"].is_number_integer()){
            incoming.message_type = root["message_type"].get<int>();
        }
    }catch(const std::exception &e){
        std::lock_guard<std::mutex> lock(mutex_);
        std::cerr << "[mqtt] invalid JSON topic=" << topic
                  << " error=" << e.what() << " payload=" << payload << "\n";
        return;
    }

    if(is_audio_message(incoming.message_type)){
        std::lock_guard<std::mutex> lock(mutex_);
        std::cerr << "[mqtt][audio-ignored] topic=" << topic
                  << " message_type=" << incoming.message_type
                  << " payload=" << payload << "\n";
        return;
    }

    if(is_device_control_message(incoming.message_type)){
        Handler handler;
        {
            std::lock_guard<std::mutex> lock(mutex_);
            std::cerr << "[mqtt][device-control] topic=" << topic
                      << " message_type=" << incoming.message_type
                      << " payload=" << payload << "\n";
            handler = device_control_handler_;
        }
        if(handler) handler(incoming);
        return;
    }

    std::lock_guard<std::mutex> lock(mutex_);
    std::cerr << "[mqtt][message] topic=" << topic
              << " message_type=" << incoming.message_type
              << " payload=" << payload << "\n";
}

} // namespace mqtt
