#ifndef DATAOUTPUTFORMATS_H
#define DATAOUTPUTFORMATS_H
#include "base_format.h"
using namespace yC;

// AVR format
// *02E99619FACDAE;
// *8D3C5EE69901BD9540078D37335F;
// *7700;
inline std::string create_AVR_format(const std::string& msg_hex) {
    return "*" + msg_hex + ";";
}

// @016CE3671C7423FFE7AB7BFCAB;
// @016CE3671AA8A800199A8BB80030A8000628F400;
// @016CE3671C747700;

// @5500068BA46CB402c18d34fc8000;
inline std::string create_MLAT_AVR_format(const std::string& msg_hex, MLAT_timestamp* timestamp) {
    //std::string signal_level_str = bin2hex(std::bitset<8>(signal_level).to_string());
    //std::cout << "signal:" << signal_level_str << std::endl;
    return "@" + bin2hex(timestamp->to_bin_string()) + msg_hex + ";";
}


// Binary Format
// <esc> "1" : 6 byte MLAT timestamp, 1 byte signal level, 2 byte Mode-AC
// <esc> "2" : 6 byte MLAT timestamp, 1 byte signal level, 7 byte Mode-S short frame
// <esc> "3" : 6 byte MLAT timestamp, 1 byte signal level, 14 byte Mode-S long frame
// <esc> "4" : 6 byte MLAT timestamp, 1 byte unused, DIP switch configuration settings, time stamp error ticks as int8_t (1 tick is 15ns) (message "4" not on Mode-S Beast classic)
// <esc><esc>: true 0x1a
// <esc> is 0x1a, and "1", "2" and "3" are 0x31, 0x32 and 0x33
inline std::string create_Binary_Format_memory(const std::string& msg_hex, char signal_level, MLAT_timestamp* timestamp) {
    std::string type;
    switch (msg_hex.size()) {
    case 4: type = '1';
        break;
    case 14: type = '2';
        break;
    case 28: type = '3';
        break;
    default: std::cerr << msg_hex << "create_Binary_Format error is not a valid binary format." << std::endl;
        throw std::runtime_error("create_Binary_Format error!");
    }


    std::string t = timestamp->to_memory() + signal_level + yC::hex2mem(msg_hex);

    // std::cout << "msg_hex.size():" << msg_hex.size() << std::endl;
    // std::cout << "hex2memory(msg_hex):" << hex2memory(msg_hex).size() << std::endl;
    // std::cout << t.size() << std::endl;
    std::string result;

    // 遍历原始字符串
    for (size_t i = 0; i < t.size(); ++i) {
        result.push_back(t[i]);  // 插入当前字符
        if (t[i] == '\x1a') {
            result.push_back('\x1a');  // 如果是 0x1a，插入另一个 0x1a
        }
    }

    return char(0x1a) + type +  result;
}

// 把要传递的信息转化成转义字符  二进制==>转义二进制
std::string packet_to_escape_format(std::string t);

inline std::string unescape_packet(std::string t) {
    std::string result;
    for (size_t i = 0; i < t.size(); ++i) {
        if (t[i] == '\x1a' && i + 1 < t.size() && t[i + 1] == '\x1a') {
            result.push_back('\x1a');  // 如果是连续的两个 \x1a，只添加一个
            ++i;  // 跳过下一个 \x1a
        } else {
            result.push_back(t[i]);  // 否则，直接添加当前字符
        }
    }
    return result;
}


//     用于dip_setting
//                           FPGA switch settings
//     Bit 0:	Data output mode(port 10002 only)         Binary	                                AVR hexdump
//     Bit 1:	Raw data frame types	                  DF11, DF17 and DF18 only	                no pre-filtering
//     Bit 2:	Timestamps within AVR format	          enabled	                                disabled
//     Bit 3:	not used
//     Bit 4:	Timestamp mode	                          GPS	                                    legacy 12MHz
//     Bit 5:	FPGA/USB handshake	                      disabled	                                enabled
//     Bit 6:	1 bit forward error correction (FEC)	  disabled	                                enabled
//     Bit 7:	Mode-A/C decoding	                      enabled	                                disabled
//                         GPS status information
// Bit 0:	Antenna status	                    good	         fail
// Bit 1:   Tracking at least 1 satellite       true	         false
// Bit 2:   Tracking at least  3 satellites     true	         false
// Bit 3:	Time value base	                    UTC time         GPS time (8sec offset)
// Bit 4:	unused
// Bit 5:	unused
// Bit 6:	unused
// Bit 7:	Daysec value range	               0 ... 86399	     1 ... 86400
inline std::string create_Binary_Format_4(MLAT_timestamp timestamp, char signal_level, char dip_setting, char time_stamp_error_ticks) {
    return char(0x1a) + "4" + timestamp.to_bin_string() + char(0xaa) + dip_setting + time_stamp_error_ticks;
}

//相对时间戳（无 GPS）：在没有连接 GPS 接收器的情况下，时间戳是一个 48 位无符号数字，
//计数 12 MHz 周期。时间戳大约每 271 天换行一次。
struct TCXO_Clock {
    unsigned long long times;

    explicit TCXO_Clock(const std::string& hex) {
        times = std::bitset<48>(hex2bin(hex)).to_ullong();
    }

    [[nodiscard]] std::string to_string() const {
        // 每个周期的时间是 1 / 12,000,000 秒
        double seconds = static_cast<double>(times) / 12000000.0;
        // 计算小时、分钟、秒
        int hours = static_cast<int>(seconds / 3600);
        seconds -= hours * 3600;
        int minutes = static_cast<int>(seconds / 60);
        seconds -= minutes * 60;
        int secs = static_cast<int>(seconds);
        // 格式化为时分秒字符串
        std::ostringstream oss;
        oss.fill('0');
        oss << hours << ":";
        oss.width(2);
        oss << minutes << ":";
        oss.width(2);
        oss << secs;
        return oss.str();
    }
};

/*
Periodic status message which is emitted every second
0x1A 0x48 0x01 0x18 SerNum Flags I.U. xTime Lat Lon Alt Sat HDOP
Fields:
     SerNum 32-bit(1) Device Serial Number
     Flags 16-bit(1) Status Flags*
     I.U. 16-bit Internal Use
     xTime 32-bit(1) Unix-Timestamp (Seconds since midnight 1970-01-01, UTC)
     Lat 32-bit(1) Latitude as 32-bit BAM 2, thus 232 ≡ 360°
     Lon 32-bit(1) Latitude as 32-bit BAM 2
     Alt 16-bit(1) Signed altitude meters
     Sat 8-bit Number of satellites used in fix
     HDOP 8-bit HDOP * 10, thus a value of 12 is HDOP 1.2
1) MSB-first
2) https://en.wikipedia.org/wiki/Binary_scaling#Binary_angles
    Status Flags:
    1xxx xxxx xxxx xxxx - GPS device detected -> Using absolute timestamp
    x1xx xxxx xxxx xxxx - GPS valid (GGA, RMC present)
    xx1x xxxx xxxx xxxx - GPS currently has a valid fix
    xxx1 xxxx xxxx xxxx - High accuracy absolute time is available via PPS
    xxxx xxxx 1xxx xxxx - TX-Queue overflow since start-up (normal if HW-handshaking is used)
    xxxx xxxx x1xx xxxx - TX-Queue overflow during last second (probably due to HW-handshaking)
    xxxx xxxx xx1x xxxx - Excessive NMEA found (other than GGA/RMC)
*/
//
// All HULC messages (Type 0x48) have the following structure:
// 0x1A 0x48 ID LEN
// Fields:
// ID: HULC Message ID
// LEN: Number of bytes following
struct HULC_Message {
    std::uint8_t head;
    std::uint8_t id;
    std::uint8_t len; // 指示下面的长度
};




struct HULC_Status_Message : HULC_Message {
    std::uint32_t SerNum{};
    std::uint16_t Flags{}; //  MSB大端字节序
    std::uint16_t I_U_{}; // Internal Use
    std::uint32_t xTime{}; // Unix-Timestamp (Seconds since midnight 1970-01-01, UTC)
    std::int32_t Lat{};
    std::int32_t Lon{};
    std::int16_t Alt{};
    std::uint8_t Sat{}; // Sat字段记录了定位过程中使用的卫星数量
    std::uint8_t HDOP{};

    [[nodiscard]] double get_HDOP() const {
        // HDOP（Horizontal Dilution of Precision） 描述的是 水平精度的衰减，即 GPS 系统的水平定位精度与卫星的几何布局有关。HDOP 数值越低，说明卫星的几何布局越好，定位精度越高。
        // 较低的 HDOP 值（例如 1-2）表示卫星信号较强，且卫星的分布较为理想，因此定位精度较高。
        // 较高的 HDOP 值（例如 5 或更高）表示卫星信号较弱，或卫星的分布较差，可能导致较差的定位精度。
        return double(HDOP) / 10.0;
    }

    void set_latitude(double latitude) {
        // 根据经纬度设置 Lat 值
        Lat = static_cast<int32_t>((latitude / 360.0) * pow(2, 32));
    }

    void set_longitude(double longitude) {
        // 根据经纬度设置 Lon 值
        Lon = static_cast<int32_t>((longitude / 360.0) * pow(2, 32));
    }

    [[nodiscard]] double get_latitude() const {
        return (static_cast<double>(Lat) / pow(2, 32)) * 360.0;
    }

    [[nodiscard]] double get_longitude() const {
        return (static_cast<double>(Lon) / pow(2, 32)) * 360.0;
    }

    [[nodiscard]] std::string get_latitude_d_m_s() const{
        return decimalToDMS(get_latitude());
    }

    [[nodiscard]] std::string get_longitude_d_m_s() const{
        return decimalToDMS(get_longitude());
    }

    [[nodiscard]] std::string get_timestamp_string() const{
        return convert_timestamp_to_string(xTime);
    }

    static std::string convert_timestamp_to_string(std::uint32_t time32) {
        std::time_t time = time32;
        std::stringstream ss;
        ss << std::put_time(std::gmtime(&time), "%Y-%m-%d %H:%M:%S"); // 使用 std::put_time 格式化日期
        return ss.str(

        );
        // 返回格式化后的字符串
        // std::time_t time = time32;
        // std::stringstream ss;
        // // 将时间戳转换为本地时间
        // ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S"); // 使用 std::localtime 格式化日期
        // return ss.str(); // 返回格式化后的字符串
        // // Unix Timestamp
        // std::time_t timestamp = xTime;
        //
        // std::tm* ptm = std::gmtime(&timestamp);
        //
        // return std::asctime(ptm);
    }


    // 转化经纬度变成 度 分 秒
    static std::string decimalToDMS(double decimalDegree) {
        int degrees = static_cast<int>(decimalDegree);
        double minutesDouble = (decimalDegree - degrees) * 60;
        int minutes = static_cast<int>(minutesDouble);
        int seconds = static_cast<int>((minutesDouble - minutes) * 60.0);
        return "(" + std::to_string(degrees) + "°" + std::to_string(minutes) + "'" + std::to_string(seconds) + "\")";
    }
    /*
    Status Flags:
    1xxx xxxx xxxx xxxx - GPS device detected -> Using absolute timestamp
    x1xx xxxx xxxx xxxx - GPS valid (GGA, RMC present)
    xx1x xxxx xxxx xxxx - GPS currently has a valid fix
    xxx1 xxxx xxxx xxxx - High accuracy absolute time is available via PPS
    xxxx xxxx 1xxx xxxx - TX-Queue overflow since start-up (normal if HW-handshaking is used)
    xxxx xxxx x1xx xxxx - TX-Queue overflow during last second (probably due to HW-handshaking)
    xxxx xxxx xx1x xxxx - Excessive NMEA found (other than GGA/RMC)
    */
    [[nodiscard]] bool GPS_device_detected() const {
        return Flags & (1 << 15); // 检查第 15 位，GPS 设备是否检测到
    }

    [[nodiscard]] bool GPS_valid() const {
        return Flags & (1 << 14); // 检查第 14 位，GPS 数据是否有效
    }

    [[nodiscard]] bool GPS_has_valid_fix() const {
        return Flags & (1 << 13); // 检查第 13 位，GPS 是否有有效定位
    }

    [[nodiscard]] bool GPS_high_accuracy_time() const {
        return Flags & (1 << 12); // 检查第 12 位，是否通过 PPS 提供高精度绝对时间
    }

    [[nodiscard]] bool TX_queue_overflow_since_startup() const {
        return Flags & (1 << 7); // 检查第 7 位，自启动以来是否发生 TX 队列溢出
    }

    [[nodiscard]] bool TX_queue_overflow_last_second() const {
        return Flags & (1 << 6); // 检查第 6 位，过去一秒内是否发生 TX 队列溢出
    }

    [[nodiscard]] bool excessive_NMEA_found() const {
        return Flags & (1 << 5); // 检查第 5 位，是否发现过多的 NMEA 数据（非 GGA/RMC）
    }

    [[nodiscard]] Json toJson() const {
        Json ret = Json::object();
        ret.append({"序列号", SerNum});
        ret.append({"状态标志", Flags});
        ret.append({"内部使用", I_U_});
        ret.append({"时间戳", get_timestamp_string()});
        ret.append({"纬度", std::to_string(get_latitude()) + " " + get_latitude_d_m_s()});
        ret.append({"经度", std::to_string(get_longitude()) + " " + get_longitude_d_m_s()});
        ret.append({"高度", Alt});
        ret.append({"卫星数量", Sat});
        ret.append({"HDOP", get_HDOP()});
        ret.append({"GPS设备检测到", GPS_device_detected()});
        ret.append({"GPS有效", GPS_valid()});
        ret.append({"GPS有效定位", GPS_has_valid_fix()});
        ret.append({"GPS高精度时间", GPS_high_accuracy_time()});
        ret.append({"启动以来TX队列溢出", TX_queue_overflow_since_startup()});
        ret.append({"过去一秒TX队列溢出", TX_queue_overflow_last_second()});
        ret.append({"发现过多NMEA数据", excessive_NMEA_found()});
        return ret;
    }


    static double decodeLatitudeFromBAM(const std::string& bigdian4) {
        std::uint32_t value;
        yC::big_endian_2_platform(bigdian4, (char*)&value);
        // BAM 格式解码公式
        // return (static_cast<double>(value) / pow(2, 32)) * 360.0;
        return (static_cast<double>(value) / pow(2, 32)) * 360.0;
    }
    std::string toBinary() {
        std::string binary = {0x1a, 0x48, 0x01, 0x18};
        binary.append(yC::platform_2_big_endian(&SerNum, 4));
        binary.append(yC::platform_2_big_endian(&Flags, 2));
        binary.append(std::string((char*)&I_U_, 2)); // 内部使用没说什么序 默认大端序
        binary.append(yC::platform_2_big_endian(&xTime, 4));
        binary.append(yC::platform_2_big_endian(&Lat, 4));
        binary.append(yC::platform_2_big_endian(&Lon, 4));
        binary.append(yC::platform_2_big_endian(&Alt, 2));
        // 没说什么序 一字节 大端小端 等同
        binary.append({(char)Sat});
        binary.append({(char)HDOP});
        return binary;
    }
};



static void hulc_big_endian_set(const std::string& msg, void* field, int start, int len) {
    auto str = msg.substr(start, len);
    yC::big_endian_2_platform(str, (char*)field);
}

static void hulc_set2(const std::string& msg, void* field, int start, int len) {
    auto it = msg.substr(start, len);
    std::memcpy(field, it.data(), len);
}
// msg 是文本二进制字符串 转义后的 1a34
static HULC_Status_Message create_HULC_Status_Message(const std::string& msg) {
    HULC_Status_Message ret{};
    hulc_big_endian_set(msg, &ret.SerNum, 4, 4);
    hulc_big_endian_set(msg, &ret.Flags, 8, 2);
    hulc_set2(msg, &ret.I_U_, 10, 2);
    hulc_big_endian_set(msg, &ret.xTime, 12, 4);
    hulc_big_endian_set(msg, &ret.Lat, 16, 4);
    hulc_big_endian_set(msg, &ret.Lon, 20, 4);
    hulc_big_endian_set(msg, &ret.Alt, 24, 2);
    hulc_set2(msg, &ret.Sat, 26, 1);
    hulc_set2(msg, &ret.HDOP, 27, 1);
    return ret;
}


struct HULC_Reply_to_command : HULC_Message {
    std::uint8_t CMD;
    std::uint8_t POO_14;
};

// 0x1A 0x48 0x01 0x18 SerNum Flags I.U. xTime Lat Lon Alt Sat HDOP
inline std::uint8_t get_id(const std::string& msg) {
    return msg[2];
}

inline std::uint8_t get_len(const std::string& msg) {
    return msg[3];
}

// Type Payload Size Description
// 0x31 4 bytes Mode-A/C raw data
// 0x32 7 bytes Mode-S Short Squitter raw data
// 0x33 14 bytes Mode-S Extended Squitter raw data
// 0x48 variable HULC Message, see below for details
// HULC Protocol uses the byte 0x1A as start-of-packet (SOP) marker. In order to avoid misinterpretation
// of normal data bytes with value 0x1A as SOP, each occurrence of data byte 0x1A is doubled in the
// data stream during transmission ('escaping'). It is thus necessary during reception to detect every
// 0x1A not followed by another 0x1A as an SOP marker and to reduce every occurrence of a double
// 0x1A to a single 0x1A data byte ('un-escaping').
// Example of a 4-byte long packet including SOP marker and 0x1A data bytes:
// Before Escaping: 1A 32 27 1A E8 57 F0 1A 6C
// During Transmission: 1A 32 27 1A 1A E8 57 F0 1A 1A 6C
// After Un-Escaping: 1A 32 27 1A E8 57 F0 1A 6C
void Binary_Format_handle_buffer(std::string& buffer, const std::string& data, const std::function<void(std::string&)>& callback);
/* Command Message (Host ==> Device)
The command-message has a simple ASCII based structure. Each message starts with a ‘#’ (0x23) and
ends with ‘<CR><LF>’ (0x0D, 0x0A). In-between are one to 16 bytes in 2-digit hexadecimal representation
using upper-case letters, separated by ‘-’ (0x2D).
For example:
    ‘#00<CR><LF>’ or hexadecimal 0x23 0x30 0x30 0x0D 0x0A
    ‘#43-02<CR><LF>’ or hexadecimal 0x23 0x34 0x33 0x2D 0x30 0x32 0x0D 0x0A
    The first byte is mandatory and holds the command while the remaining bytes are parameters.
    Available commands depend on the selected protocol and are discussed in the respective protocol
    section.
*/

std::string mode_s_msg_packet_to_server_packet(std::uint32_t id, std::string packet);



// 1a34  radarcape 状态帧消息
// https://wiki.jetvision.de/wiki/Radarcape:Version_History#Status_Frame_0x34_contents_were_extended_with_GPS_and_UTC_information
// 状态帧0x34内容已扩展为 GPS 和 UTC 信息
// 当选择 GPS 时间戳时，状态帧由 1PPS 脉冲触发，在传统 12MHz 时间戳的情况下随机触发。
// 状态帧包含有效的时间戳
// 信号电平值为零/保留


#define SETGET(name, pos) void set_##name(bool value) { set(pos, value); } \
bool get_##name() { return get(pos); }

#define SETGET2(Type, name, pos) void set_##name(Type value) { set(pos, (uint8_t)value); } \
Type get_##name() { return (Type)get(pos); }

struct BYTE_Settings {
protected:
    uint8_t settings{};  // 8 位的字段，存储所有设置
    void set(uint8_t pos, bool value) {
        if (value) {
            // 设置指定位置的位为 1
            settings |= (1 << pos);
        } else {
            // 设置指定位置的位为 0
            settings &= ~(1 << pos);
        }
    }
    [[nodiscard]] bool get(uint8_t pos) const {
        // 获取指定位置的位值
        return (settings >> pos) & 0x01;
    }
};
struct FPGA_Setting : BYTE_Settings {
    enum class Data_Output_Mode { AVR_hexdump, Binary };
    enum class Raw_Data_Frame_Type { No_Pre_Filtering, DF11_17_18_only };
    enum class Timestamp_Mode { Legacy_12MHz, GPS };
    SETGET2(Data_Output_Mode, data_output_mode, 0)
    SETGET2(Raw_Data_Frame_Type, raw_data_frame_type, 1)
    SETGET(timestamps_within_AVR_format, 2)
    SETGET2(Timestamp_Mode, timestamp_mode, 4)
    SETGET(serial_flow_control, 5)
    SETGET(FEC, 6)  // 1位转发错误校正
    SETGET(mode_ac_decoding , 7)
    Json toJson() {
        Json ret = Json::object();
        ret.append({"Data_Output_Mode", to_string(get_data_output_mode())});
        ret.append({"Raw_Data_Frame_Type", to_string(get_raw_data_frame_type())});
        ret.append({"timestamps_within_AVR_format", get_timestamps_within_AVR_format()});
        ret.append({"timestamps_mode", to_string(get_timestamp_mode())});
        ret.append({"serial_flow_control", get_serial_flow_control()});
        ret.append({"1位转发错误校正", get_FEC()});
        ret.append({"mode_ac_decoding", get_mode_ac_decoding()});
        return ret;
    }

};

struct GPS_Setting : BYTE_Settings {
    enum class Time_Value_Base { UTC, GPS };
    enum class Daysec_Range { R_0_86399, R_1_86400 };
    SETGET(antenna_status, 0)               // 位 0: 天线状态
    SETGET(tracking_at_least_1_satellite, 1) // 位 1: 至少跟踪 1 颗卫星
    SETGET(tracking_at_least_3_satellites, 2) // 位 2: 至少跟踪 3 颗卫星
    SETGET2(Time_Value_Base, time_value_base, 3)  // 位 3: 时间值基数 (UTC/GPS)
    SETGET(unused4, 4)                      // 位 4: 保留
    SETGET(unused5, 5)                      // 位 5: 保留
    SETGET(unused6, 6)                      // 位 6: 保留
    SETGET2(Daysec_Range, daysec_range, 7)           // 位 7: Daysec 值范围
    Json toJson() {
        Json ret = Json::object(); // 创建 JSON 对象
        ret.append({"antenna_status", get_antenna_status()});
        ret.append({"至少跟踪 1 颗卫星", get_tracking_at_least_1_satellite()});
        ret.append({"至少跟踪 3 颗卫星", get_tracking_at_least_3_satellites()});
        ret.append({"timestamps_mode", to_string(get_time_value_base())});
        ret.append({"daysec_range", to_string(get_daysec_range())});
        return ret;
    }
};

struct Radarcape_STATUS_Message {
    FPGA_Setting fpga_settings;
    std::uint8_t pps_nanosecond_offset{}; // 包含 1PPS 事件时纳秒计时器的偏移量，单位为 15.625ns。正常值范围为 -3 ... +3。
    GPS_Setting gps_settings;
    void set_pps_nanosecond(double value) {
        if (value < 0.0 || value > 4000) {
            std::cerr << "Invalid value. Must be in range [0.0, 4000.0]." << std::endl;
            return;
        }
        pps_nanosecond_offset = static_cast<std::uint8_t>((value)/15.625);
    }
    [[nodiscard]] double get_pps_nanosecond() const {
        return (double)pps_nanosecond_offset * 15.625;
    }
    std::string toBinary() {
        std::string binary = {0x1a, 0x34};
        binary.append(reinterpret_cast<const char*>(&fpga_settings), 1);
        binary.append(reinterpret_cast<const char*>(&pps_nanosecond_offset), 1);
        binary.append(reinterpret_cast<const char*>(&gps_settings), 1);
        return binary;
    }

    Json toJson() {
        Json ret = Json::object();
        ret.append({"pps_nanosecond_offset", get_pps_nanosecond()});
        ret.append({"fpga_settings", fpga_settings.toJson()});
        ret.append({"gps_settings", gps_settings.toJson()});
        return ret;
    }

};

// 消息5字节
//
static Radarcape_STATUS_Message create_Radarcape_STATUS_Message(const std::string& msg_5) {
    std::string msg = yC::big_endian_2_platform(msg_5.substr(2));
    Radarcape_STATUS_Message ret{};
    std::memcpy(&ret, (void*)(msg.data()), 3);
    return ret;
}



#undef SETGET
#undef SETGET2

#endif
