//
// Created by magino on 9. 3. 2020.
//

#ifndef HEADER_H
#define HEADER_H

#include <mqttcomm/RfidMqttClient.h>
#include "RFID/WriteSectorDataModel.h"
#include "helpers/ToBytes.h"

class RfidMqttClient;

class Header {
private:
    RfidMqttClient& _client;
public:
    uint16_t recipeId;
    uint16_t recipeVersion;

    uint64_t releaseDateTime;
    uint64_t serialNumber;

    uint64_t orderDateTime;
    uint64_t dispenseDateTime;

    uint16_t status;
    uint8_t pieceListLength;
    uint8_t procedureLength;

    ~Header() = default;

    Header(std::vector<uint8_t> data, RfidMqttClient& client): _client(client) {
        recipeId = (data[0] << 8) | data[1];
        recipeVersion = (data[2] << 8) | data[3];


        releaseDateTime = data[11] ;
        releaseDateTime = (releaseDateTime << 8 ) + data[10] ;
        releaseDateTime = (releaseDateTime << 8 ) + data[9] ;
        releaseDateTime = (releaseDateTime << 8 ) + data[8] ;
        releaseDateTime = (releaseDateTime << 8 ) + data[7] ;
        releaseDateTime = (releaseDateTime << 8 ) + data[6] ;
        releaseDateTime = (releaseDateTime << 8 ) + data[5] ;
        releaseDateTime = (releaseDateTime << 8 ) + data[4] ;


        serialNumber = data[19] ;
        serialNumber = (serialNumber << 8 ) + data[18] ;
        serialNumber = (serialNumber << 8 ) + data[17] ;
        serialNumber = (serialNumber << 8 ) + data[16] ;
        serialNumber = (serialNumber << 8 ) + data[15] ;
        serialNumber = (serialNumber << 8 ) + data[14] ;
        serialNumber = (serialNumber << 8 ) + data[13] ;
        serialNumber = (serialNumber << 8 ) + data[12] ;


        orderDateTime = data[27] ;
        orderDateTime = (orderDateTime << 8 ) + data[26] ;
        orderDateTime = (orderDateTime << 8 ) + data[25] ;
        orderDateTime = (orderDateTime << 8 ) + data[24] ;
        orderDateTime = (orderDateTime << 8 ) + data[23] ;
        orderDateTime = (orderDateTime << 8 ) + data[22] ;
        orderDateTime = (orderDateTime << 8 ) + data[21] ;
        orderDateTime = (orderDateTime << 8 ) + data[20] ;


        dispenseDateTime = data[35] ;
        dispenseDateTime = (dispenseDateTime << 8 ) + data[34] ;
        dispenseDateTime = (dispenseDateTime << 8 ) + data[33] ;
        dispenseDateTime = (dispenseDateTime << 8 ) + data[32] ;
        dispenseDateTime = (dispenseDateTime << 8 ) + data[31] ;
        dispenseDateTime = (dispenseDateTime << 8 ) + data[30] ;
        dispenseDateTime = (dispenseDateTime << 8 ) + data[29] ;
        dispenseDateTime = (dispenseDateTime << 8 ) + data[28] ;


        status = (data[36] << 8) | data[37];
        pieceListLength = data[38];
        procedureLength = data[39];
    }

    bool SetDispenseDateTime(uint64_t dispenseDateTime) {
        std::vector<uint8_t> byteData;
        byteData.reserve(8);
        ToBytes::Split64BitsToBytes(byteData, dispenseDateTime);

        auto jsonObjects = nlohmann::json::array();
        WriteSectorDataModel sector8Data;
        sector8Data.data.insert(sector8Data.data.begin(), byteData.begin(), byteData.begin()+4);
        sector8Data.sector = 8+3;//11
        WriteSectorDataModel sector9Data;
        sector9Data.data.insert(sector9Data.data.begin(), byteData.begin()+4, byteData.end());
        sector9Data.sector = 9+3;//12

        jsonObjects.emplace_back(sector8Data);
        jsonObjects.emplace_back(sector9Data);

        nlohmann::json output;
        output["write_multi"] = jsonObjects;
        if(_client.SendMessage(output.dump())) {
            dispenseDateTime = dispenseDateTime;
            return true;
        }
        std::cout << "Set Dispense DateTime Failed" << std::endl;
        return false;
    }

    bool SetStatus(uint16_t status) {
        // i can write whole sector at once so I need to include with status also _pieceListLength and _procedureLength = 4bytes
        std::vector<uint8_t> byteData;
        byteData.reserve(4);
        ToBytes::Split16bitsToBytes(byteData, status);
        byteData.push_back(pieceListLength);
        byteData.push_back(procedureLength);

        auto jsonObjects = nlohmann::json::array();
        WriteSectorDataModel sector10Data(byteData,10+3);
        jsonObjects.emplace_back(sector10Data);

        nlohmann::json output;
        output["write_multi"] = jsonObjects;
        if(_client.SendMessage(output.dump())) {
            status = status;
            return true;
        }
        std::cout << "Set Status Failed" << std::endl;
        return false;
    }

    uint8_t GetPieceListLength() const { return pieceListLength; }
    uint8_t GetProcedureLength() const { return procedureLength; }
};

#endif //HEADER_H