#ifndef GENERIC_BARRIER_H
#define GENERIC_BARRIER_H
#include "barrier.h"
#include "barrier_properties.h"

#include <tuple>

#include "recognize_data.h"

namespace zsy
{
    struct DoorReq
    {
        std::string uuid;
        std::string deviceNo; //设备编号
        uint64_t id; //自增id
        std::string carNo; //车牌号
    };

    inline void from_json(const nlohmann::json &j, DoorReq &o)
    {
        PARSE_JSON(uuid, o.uuid);
        PARSE_JSON(deviceNo, o.deviceNo);
        PARSE_JSON(id, o.id);
        PARSE_JSON(carNo, o.carNo);
    }

    struct Body
    {
        int delay = 500;
        int value;
        int io;
    };

    struct Payload
    {
        std::string type = "gpio_out";
        Body body;
    };

    struct BarrierBcd
    {
        std::string id;
        std::string sn;
        std::string name = "gpio_out";
        std::string version = "1.0";
        long timestamp;
        Payload payload;
    };

    inline void to_json(nlohmann::json &j, const Body &b)
    {
        j = nlohmann::json{{"delay", b.delay}, {"value", b.value}, {"io", b.io}};
    }

    inline void to_json(nlohmann::json &j, const Payload &p)
    {
        j = nlohmann::json{{"type", p.type}, {"body", p.body}};
    }

    inline void to_json(nlohmann::json &j, const BarrierBcd &bb)
    {
        j = nlohmann::json{
            {"id", bb.id}, {"sn", bb.sn}, {"name", bb.name},
            {"version", bb.version}, {"timestamp", bb.timestamp},
            {"payload", bb.payload}
        };
    }

    struct PlateResult
    {
        std::string imageFile;
        std::string license;
        std::string telephone;
    };

    struct Result
    {
        PlateResult plateResult;
    };

    struct AlarmInfoPlate
    {
        int channel;
        std::string deviceName;
        std::string ipaddr;
        Result result;
        std::string serialno;
    };

    struct RecognizeResult
    {
        AlarmInfoPlate alarmInfoPlate;
    };

    inline void from_json(const nlohmann::json &j, PlateResult &data)
    {
        if (j.contains("imageFile")) j.at("imageFile").get_to(data.imageFile);
        else
        {
            LOGGER_ERROR("imageFile 不存在");
        }
        if (j.contains("license")) j.at("license").get_to(data.license);
        else
        {
            LOGGER_ERROR("license 不存在");
        }
    }

    inline void from_json(const nlohmann::json &j, Result &data)
    {
        if (j.contains("plateResult")) j.at("plateResult").get_to(data.plateResult);
        else if (j.contains("PlateResult")) j.at("PlateResult").get_to(data.plateResult);
        else
        {
            LOGGER_ERROR("plateResult 不存在");
        }
    }

    inline void from_json(const nlohmann::json &j, AlarmInfoPlate &data)
    {
        if (j.contains("result")) j.at("result").get_to(data.result);
        else
        {
            LOGGER_ERROR("result 不存在");
        }
        if (j.contains("serialno")) j.at("serialno").get_to(data.serialno);
        else
        {
            LOGGER_ERROR("serialno 不存在");
        }
    }

    inline void from_json(const nlohmann::json &j, RecognizeResult &data)
    {
        if (j.contains("alarmInfoPlate")) j.at("alarmInfoPlate").get_to(data.alarmInfoPlate);
        else if (j.contains("AlarmInfoPlate")) j.at("AlarmInfoPlate").get_to(data.alarmInfoPlate);
        else
        {
            LOGGER_ERROR("alarmInfoPlate 不存在");
        }
    }

    class GenericBarrier : public Barrier
    {
        BarrierProperties config;
        inline static std::unordered_map<std::string, std::string> tasks;
        inline static std::mutex tasks_mutex;
    public:
        explicit GenericBarrier(const BarrierProperties &config);

        void open() override;

        bool isFront() override;

        std::string sn() override;

        std::string name() override;

        std::shared_ptr<std::istream> resolvePhoto(const std::string &imageFile) override;

        static std::tuple<bool, std::shared_ptr<RecognizeData>, std::string, std::string> parseRecognizeResult(const std::string &jsonStr);
    };
} // zsy

#endif //GENERIC_BARRIER_H
