#ifndef INTERFACE_H
#define INTERFACE_H
///////////////////////////////////////////////////////////////////////////////////////////

#include <string>
#include <list>
#include <array>
#include <map>
#include <mutex>
#include <sstream>
#include <iostream>

#include <unordered_set>

///////////////////////////////////////////////////////////////////////////////////////////

#include "nlohmann/json.hpp"

#include "../../client2.h"

///////////////////////////////////////////////////////////////////////////////////////////

class Front;

///////////////////////////////////////////////////////////////////////////////////////////

/*#define STAT_DATA_BASE_NODE_ID			100
#define THREE_SECS_DATA_BASE_NODE_ID	200
#define SOE_COMTRADE_BASE_NODE_ID		300
#define HIS_DATA_BASE_NODE_ID			400
#define NEW_HIS_DATA_BASE_NODE_ID		500
#define RECALL_HIS_DATA_BASE_NODE_ID	600
#define RECALL_ALL_DATA_BASE_NODE_ID	700*/

///////////////////////////////////////////////////////////////////////////////////////////

//单条补招时间结构
class RecallInfo
{
public:
	long long starttime;//开始时间
	long long endtime;	//结束时间
};

//测点记录的补招结构
class RecallMonitor
{
public:
    std::string recall_guid; // 本次补招的唯一标识 GUID
    int recall_status;      //补招状态 0-未补招 1-补招中 2-补招完成 3-补招失败 4-无数据
    std::string StartTime; //数据补招起始时间
	std::string EndTime;   //数据补招结束时间
	std::string STEADY;    //补招历史统计数据标识 0-不补招；1-补招     
	std::string VOLTAGE;   //补招暂态事件标识     0-不补招；1-补招
};

// ====== ★新增：下载/列目录阶段枚举与结果枚举 ======
enum class RecallPhase {
    IDLE = 0,
    LISTING,        // 正在请求并等待“目录文件名列表”
    DOWNLOADING     // 正在按队列逐个下载
};

enum class ActionResult {
    PENDING = -1,   // 还未返回
    FAIL    = 0,
    OK      = 1
};

// ====== ★修改：扩展 RecallFile，支持“多目录 + 文件筛选 + 串行下载”的状态机 ======
class RecallFile
{
public:
    std::string recall_guid; // 本次补招的唯一标识 GUID
    int recall_status;      // 补招状态 0-未补招 1-补招中 2-补招完成 3-补招失败
    std::string StartTime;  // 数据补招起始时间（yyyy-MM-dd HH:mm:ss）
    std::string EndTime;    // 数据补招结束时间（yyyy-MM-dd HH:mm:ss）
    std::string STEADY;     // 补招历史统计数据标识 0-不补招；1-补招
    std::string VOLTAGE;    // 补招暂态事件标识   0-不补招；1-补招

    //暂态文件用
    bool        direct_mode = false;     // 直下文件开关：true 表示不按时间窗，仅按目标文件名
    std::string    target_filetimes;           // 直下文件匹配时间点（yyyyMMdd_HHmmss），仅 direct_mode=true 时有效

    // ★新增：按“目录名 -> 文件名列表”的映射；由“其他线程”在目录请求成功后回填
    std::map<std::string, std::vector<tag_dir_info>> dir_files;

    // ★新增：候选目录（可扩展）
    std::vector<std::string> dir_candidates{ 
        "/cf/COMTRADE",
        "/bd0/COMTRADE",
        "/sd0/COMTRADE",
        "/sd0:1/COMTRADE"
    };

    // ★新增：状态机运行时变量
    RecallPhase phase = RecallPhase::IDLE;
    int         cur_dir_index = 0;          // 正在尝试的目录下标
    std::string cur_dir;                    // 正在处理的目录

    // ★新增：列目录/下载请求“回执位”，由其他线程置位
    ActionResult list_result     = ActionResult::PENDING;  // 当前目录的列举结果
    ActionResult download_result = ActionResult::PENDING;  // 当前文件的下载结果

    // ★新增：下载队列（已筛选出在时间窗内的文件，含完整路径）
    std::list<std::string> download_queue;      //一个时间可能对应多个文件
    std::string            downloading_file; // 当前正在下载的文件（完整路径）

    std::unordered_set<std::string> required_files; // 本次应当下载成功的文件全集
    std::unordered_set<std::string> file_success;   // 已下载成功的文件集合

    // ★新增：一个便捷复位
    void reset_runtime(bool keep_direct = false)
    {
        phase            = RecallPhase::IDLE;
        cur_dir_index    = 0;
        cur_dir.clear();
        list_result      = ActionResult::PENDING;
        download_result  = ActionResult::PENDING;
        download_queue.clear();
        downloading_file.clear();
        dir_files.clear();

        required_files.clear();
        file_success.clear();

        // ★新增：按需保留直下文件开关和目标名
        if (!keep_direct) {
            direct_mode = false;
            target_filetimes.clear(); // ▲列表清空
        }
    }
};

enum class RecallStatus {
    NOT_STARTED = 0, // 未补招
    RUNNING     = 1, // 补招中
    DONE        = 2, // 补招完成
    FAILED      = 3, // 补招失败
    EMPTY       = 4  // 无补招数据
};

// 本轮要下发的一条任务（每个终端最多一条）
struct RecallTask {
    std::string dev_id;
    std::string start_time;
    std::string end_time;
    std::string monitor_index;
};

//日志补招结构类,当前不使用
class JournalRecall 
{
public:
    std::string DevID;     //装置号
	std::string MonitorID; //线路监测点号
	std::string StartTime; //数据补招起始时间
	std::string EndTime;   //数据补招结束时间
	std::string STEADY;    //补招历史统计数据标识 0-不补招；1-补招     
	std::string VOLTAGE;   //补招暂态事件标识     0-不补招；1-补招
};

//录波文件和暂态事件
class qvvr_data
{
    public:
        bool is_pair;
	    bool				used_status;    //是否占用
	    int					QVVR_type;      //暂态类型
	    uint64_t			QVVR_time;	    //暂态开始时间 unsigned longlong
	    double				QVVR_PerTime;   //暂态持续时间
	    double				QVVR_Amg;       //暂态幅值
        int                 phase;          //相别(仅瞬态上送)0-A 1-B 2-C 3-AB 4-BC 5-CA 其他-ABC/异常
};

class qvvr_file
{
    public:
        bool used_status;
        int  file_time_count;     //组内文件下载时间计数（第一个文件下载后十分钟内如果其他文件没下载全或者下载全了没匹配事件则将已下载的文件都移到备份区comtrade_bak）
        bool is_download;       //文件是否下载完全，最后一个文件下载成功后对比成功则更新这个标志
        bool is_pair;           //文件是否和事件匹配，从comtrade/mac/路径下取file_download中的cfg文件提取时间和持续时间来匹配，匹配后接口发送这组file_download全部文件，发送成功后删除这组文件，然后更新事件中的文件列表
        std::list<std::string> file_name;  //文件列表（文件列表上送后就记录）
        std::list<std::string> file_download;  //文件已下载列表(每次列表上送会有多个文件，多个文件都下载完全则开始匹配，每次更新都去重并对比file_name）
};

class qvvr_event
{
    public:
        std::vector<qvvr_data> qvvrdata;    //暂态事件列表
        std::vector<qvvr_file> qvvrfile;    //暂态文件组列表
};

////////////////////////////////////////////////////////////////台账更新用

class update_monitor 
{
public:
	std::string monitor_id;			//监测点id
    std::string terminal_id;		//监测点的终端id
    std::string monitor_name;		//监测点名
    std::string logical_device_seq;	//监测点序号
    std::string voltage_level;		//监测点电压等级
    std::string terminal_connect;	//监测点接线方式
    std::string timestamp;			//更新时间
	std::string status;				//监测点状态
    std::string LineLogLevel;		//监测点日志级别
    double PT1;                 // 电压变比1
    double PT2;                 // 电压变比2
    double CT1;                 // 电流变比1
    double CT2;                 // 电流变比2

};

//终端台账
class update_dev 
{
public:
    std::string guid;  // ★新增：供发送回复使用

    std::string DevLogLevel;		//装置日志级别
	std::string terminal_id;
    std::string terminal_name;
    std::string org_name;
    std::string maint_name;
    std::string station_name;
    std::string tmnl_factory;
    std::string tmnl_status;
    std::string dev_type;
    std::string dev_key;
    std::string dev_series;
    std::string addr_str;       //装置ip
    std::string port;           //装置端口
    std::string timestamp;    //更新时间
    std::string Righttime;      //对时
	std::string processNo;
	std::string maxProcessNum;
    std::string mac;            // 装置MAC地址，接口中从addr_str获取，因为ip和mac放同一位置

    std::vector<update_monitor> line;
};

////////////////////////////////////////////////////////////////////台账更新用

//监测点台账
class ledger_monitor 
{
public:
	std::string monitor_id;			//监测点id
    std::string terminal_id;		//监测点的终端id
    std::string monitor_name;		//监测点名
    std::string logical_device_seq;	//监测点序号
    std::string voltage_level;		//监测点电压等级
    std::string terminal_connect;	//监测点接线方式
    std::string LineLogLevel;		//监测点日志级别
    std::string timestamp;			//更新时间
	std::string status;				//监测点状态
    double PT1;                 // 电压变比1
    double PT2;                 // 电压变比2
    double CT1;                 // 电流变比1
    double CT2;                 // 电流变比2

    //暂态事件
    qvvr_event qvvrevent;   

    //补招列表
    std::list<RecallMonitor> recall_list;   //事件
    std::list<RecallFile> recall_list_static;//稳态文件

    //定值list
    std::list<float> set_values;
    std::vector<DZ_TAB_STRUCT> dz_info_list; //定值信息列表

};

//终端台账
class terminal_dev 
{
public:
    //int dev_index;

    std::string guid;   //正在进行的guid
    int busytype;       //业务类型，使用状态机
    int isbusy;         //业务进行标志
    int busytimecount;  //业务进行计时

    //内部定值list
    std::list<ushort> internal_values; 
    std::vector<NameFixValue> dz_internal_info_list; //内部定值信息列表
    std::vector<DZ_kzz_bit> control_words;

    std::string DevLogLevel;		//装置日志级别

	std::string terminal_id;
    std::string terminal_name;
    std::string org_name;
    std::string maint_name;
    std::string station_name;
    std::string tmnl_factory;
    std::string tmnl_status;
    std::string dev_type;
    std::string dev_key;
    std::string dev_series;
    std::string addr_str;       //装置ip
    std::string port;           //装置端口
    std::string timestamp;    //更新时间
    std::string Righttime;      //对时
	std::string processNo;
	std::string maxProcessNum;
    std::string mac;            // 装置MAC地址，接口中从addr_str获取，因为ip和mac放同一位置

    std::vector<ledger_monitor> line;
};

//icd模型
class icd_model 
{
public:
	std::string model_id;		//模型id
    std::string tmnl_type;		//终端类型
	std::string tmnl_type_id;	//终端类型id
    std::string tmnl_factory;	//终端厂家
    std::string file_name;		//文件名
	std::string file_path;		//文件路径
    std::string updatetime;		//更新时间

    icd_model() = default;
};

class queue_data_t //发送数据结构类
{ 
public: 
	int				monitor_no;		   //监测点排号
	std::string		strTopic;		   //发送topic
	std::string		strText;		   //发送的json字符串
	std::string	    mp_id;             //监测点id
    std::string     tag;              //消息tag
    std::string     key;                // 消息key
}; 

//台账更新回复
struct DeviceReply {
    std::string deviceId;
    int code;
    std::string result;
};

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// SOE 事件类
class CEventData {
public:
    int nDataType;                 // 告警 SOE 事件类型
    std::string type;              // 参数等级 type 类型
    std::string triggerFlag;       // 告警触发指标名称
    int nIndex;                    // 数据在每条线路值数组中的位置
    std::string DO;                // 数据对象名
    std::string DA;                // 数据属性名
    std::string strFullName;       // 数据对象名 $ 数据属性名
};

// 数据值类
class CDataValue {
public:
    std::string strName;           // 数据名
    float fValue;                  // 数据值
    bool bIsValue;                 // 数据是否赋值成功标识
    int nIndex;                    // 数据在每条线路值数组中的位置
    std::string type;              // 参数等级 type 类型
    std::string DO;                // 数据对象名
    std::string DA;                // 数据属性名
    std::string strFullName;       // 数据对象名 $ 数据属性名
    std::string strCoefficient;    // 数据系数(字符型)
    float fCoefficient;            // 数据系数(浮点型)
    std::string strOffset;         // 起始序号偏移量(字符型)
    int iOffset;                   // 起始序号偏移量(整型)
    bool bIsAngle;                 // 角度标志
    bool bPlt;                     // 长时闪变标识：true-长时闪变 false-短时闪变
    std::string BaseFlag;          // 历史数据部分新增指标 BaseFlag
    std::string LimitUp;           // 历史数据部分新增指标 LimitUp
    std::string LimitDown;         // 历史数据部分新增指标 LimitDown

    CDataValue()
        : fValue(0.0f), bIsValue(false), nIndex(0),
          fCoefficient(1.0f), iOffset(0), bIsAngle(false), bPlt(false) {}
};

// 相别(A、B、C、T)类
class CSequence {
public:
    std::string strSValue;         // 相别值 例：7：ABC三项，8：T相，112：AB、BC、CA三项
    std::string strSeq;            // 相别 例：A、B、C、T
    std::string type;              // 参数等级 type 类型
    std::list<CDataValue*> DataValueList; // 数据值链表
};

// 数据项类
class CItem {
public:
    std::string strItemName;       // 数据项名
    std::string strItemValue;      // 数据项值
    std::string type;              // 参数等级 type 类型
    std::list<CSequence*> SequenceList; // 相别列表
};

// 监测点类
class CMonitor {
public:
    std::string strMonitor;        // 监测点名
    std::string type;              // 参数等级 type 类型
    std::list<CItem*> ItemList;    // 数据项链表
};

// 数据类型类
class CDataType {
public:
    int iDataType;                      // 数据类型值：1-稳态 2-闪变 3-暂态
    std::string type;                   // 参数等级 type 类型
    int BaseFlag1;                      // 记录基础数据总个数
    int BaseFlag0;                      // 记录非基础数据个数
    std::list<CMonitor*> MonitorList;   // 监测点列表
    std::list<CEventData*> SOEList;     // 暂态事件列表

    CDataType() : iDataType(0), BaseFlag1(0), BaseFlag0(0) {}
};

// 队列生产者发送主题类
class CTopic {
public:
    std::string strTopic;               // 队列生产者发送的主题名
    std::list<CDataType*> DataTypeList; // 数据类型链表
};

///////////////////////////////////////////////////////////////////////////////////////////////

// XML 解析配置类
class XmlConfig {
public:
    std::string WavePhasicFlag;    // 是否分相 0-不分相 1-分相
    std::string WavePhasicA;
    std::string WavePhasicB;
    std::string WavePhasicC;
    std::string UnitOfTimeUnit;     // 暂态事件持续单位：0-毫秒 1-秒
    std::string ValueOfTimeUnit;    // 上送值时间：UTC 或 北京时间
    std::string WaveTimeFlag;       // 录波文件时间：UTC 或 北京时间
    std::string IEDname;            // 例：PQMonitor
    std::string LDevicePrefix;      // 例：PQM
    std::list<CEventData*> SOEList; // SOE 告警事件链表
};

// 数据库模型表数据类
class XmlDataBase {
public:
    std::string MODEL_ID;          // 模型编码 GUID
    std::string TMNL_TYPE;         // 终端型号
    std::string TMNL_FACTORY;      // 终端厂家
    std::string FILE_PATH;         // 远端模型文件路径
    std::string FILE_NAME;         // 远端文件名
    std::string updatetime;        // 更新时间
};

class Xmldata
{
public:
	XmlDataBase xmlbase;        //模型数据
	XmlConfig xmlcfg;           //icd映射文件解析数据
	std::list<CTopic*> topicList;    //队列发送主题链表
	bool updataflag = true;     //更新标志
};

////////////////////////////////////////////////////////////////////////////////////////////////////////

//台账更新结构/////////////////////////////////////////////
#define MAX_UPDATEA_NUM 10
typedef struct trigger_update_xml_t trigger_update_xml_t;
struct trigger_update_xml_t {
    std::vector<update_dev> new_updates;
    std::vector<update_dev> modify_updates;
    std::vector<update_dev> delete_updates;
    std::vector<update_dev> work_updates;

    trigger_update_xml_t() = default;
};

//实时触发结构////////////////////////////////////////////////////////
#define MAX_TRIGGER_NUM 300
typedef struct trigger_t trigger_t;
struct trigger_t{
	int dev_idx;
	int line_id;
	int real_data;
	int soe_data;
	int limit;
	int count;
};
typedef struct trigger_3s_xml_t trigger_3s_xml_t;
struct trigger_3s_xml_t{
	int			work_trigger_num;
	int			new_trigger_num;
	int			delete_trigger_num;
	int			modify_trigger_num;
	trigger_t	work_triggers[MAX_TRIGGER_NUM];
	trigger_t	new_triggers[MAX_TRIGGER_NUM];
	trigger_t	delete_triggers[MAX_TRIGGER_NUM];
	trigger_t	modify_triggers[MAX_TRIGGER_NUM];
};

//补招触发结构//////////////////////////////////////////////////////////
#define MAX_RECALL_NUM 300
typedef struct recall_t recall_t;
struct recall_t{ 
	std::string     line_id;
	long long		start_time;	 //待召唤日志起始时间
	long long		end_time;	 //待召唤日志结束时间
	int need_steady;
	int need_voltage; 
};
typedef struct recall_xml_t recall_xml_t;
struct recall_xml_t{
	int			work_recall_num;
	int			new_recall_num; 
	recall_t	work_recalls[MAX_RECALL_NUM];
	recall_t	new_recalls[MAX_RECALL_NUM]; 
};

///////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////interface的函数声明

std::string parse_model_cfg_web_one(const std::string& terminal_type);

int parse_device_cfg_web();
int parse_model_cfg_web();

void qvvr_test();
void Fileupload_test();

extern std::vector<terminal_dev> terminal_devlist;
extern std::mutex ledgermtx;

//////////////////////////////////////////////////////////////////////////////////cfg_parse的函数声明

void init_config();
void Set_xml_nodeinfo();
void Set_xml_nodeinfo_one(const std::string& dev_type);

void check_3s_config();
void check_ledger_update();
void create_recall_xml();

double sGetMsTime();
std::string get_current_time();

bool is_blank(const std::string& str);

void printTerminalDevMap(const std::map<std::string, terminal_dev>& terminal_dev_map);

void upload_data_test();

////////////////////////////////////////////////////////////////////////////////mq

extern std::mutex queue_data_list_mutex;
extern std::list<queue_data_t> queue_data_list;

/////////////////////////////////////////////////////////////////////////////////主函数类声明

//std::string get_front_msg_from_subdir();

extern std::string FRONT_PATH;
extern int g_front_seg_index;
extern int g_front_seg_num;

void* cloudfrontthread(void* arg);
bool parse_param(int argc, char* argv[]);

struct ThreadArgs {
    int argc;
    char **argv;
};

//////////////////////////////////////////////////////////////////////////////////主要架构

/* 常量定义 */
#define THREAD_CONNECTIONS 10        // 最大线程数
#define MONITOR_INTERVAL 1           // 监控间隔(秒)

/* 线程状态枚举 */
typedef enum {
    THREAD_RUNNING,     // 0:运行中
    THREAD_STOPPED,     // 1:正常停止  
    THREAD_RESTARTING,  // 2:重启中
    THREAD_CRASHED      // 3:异常崩溃
} thread_state_t;

/* 线程控制结构体 */
typedef struct {
    pthread_t tid;          // 线程ID
    int index;              // 线程编号(0~CONNECTIONS-1)
    thread_state_t state;   // 当前状态
    pthread_mutex_t lock;   // 线程专用互斥锁
} thread_info_t;

///////////////////////////////////////////////////////////////////////////////////////上送数据的json格式
// 单条 DataArray 数据
struct DataArrayItem {
    int DataAttr;
    time_t  DataTimeSec;
    time_t  DataTimeUSec;
    int DataTag;
    std::string Data;
};

// Msg 对象
struct MsgObj {
    int Cldid;
    int DataType;
    int DataAttr;
    int DsNameIdx;
    std::vector<DataArrayItem> DataArray;
};

// 整体
struct FullObj {
    std::string mac;
    int Mid;
    int Did;
    int Pri;
    int Type;
    MsgObj Msg;
};

// nlohmann序列化接口
void to_json(nlohmann::json& j, const DataArrayItem& d);
void to_json(nlohmann::json& j, const MsgObj& m);
void to_json(nlohmann::json& j, const FullObj& f);

/////////////////////////////////////////////////////////////////////云平台下发指令的解析
struct MsgParsed {
    int type;               // 指令编号
    std::string name;       // 文件名/目录名
    int cldid;              // 测点号
    int datatype;           // 指令细分
    int operate;            // 操作读写
    std::vector<float> dataArray_f;     // 定值写入，严格按照顺序
    std::vector<uint16_t> dataArray_us; // 内部定值写入，严格按照顺序

    bool ok;
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////提供给通讯部分调用的函数

std::vector<DeviceInfo> GenerateDeviceInfoFromLedger(const std::vector<terminal_dev>& terminal_devlist);//接口读取台账后，再调用这个将台账拷贝过来

std::string generate_json(  //构造装置主动上送数据的报文
    const std::string mac,
    int Mid,    //需应答的报文订阅者收到后需以此ID应答，无需应答填入“-1”
    int Did,    //设备唯一标识Ldid，填入0代表Ndid。
    int Pri,    //报文处理的优先级
    int Type,   //消息类型
    int Cldid,  //逻辑子设备ID，0-逻辑设备本身，无填-1
    int DataType,   //数据类型，0-表示以数据集方式上送
    int DataAttr,   //数据属性：无“0”、实时“1”、统计“2”等。
    int DsNameIdx,  //数据集序号（以数据集方式上送），无填-1
    const std::vector<DataArrayItem>& dataArray     //数据数组。
);

//暂态事件接口
bool append_qvvr_event(const std::string& terminal_id,
                              int              logical_seq,      // 监测点序号（如 1）
                              int              nType,            // 事件类型
                              double           fPersisstime_sec, // 持续时间（秒）
                              double           fMagnitude_pu,    // 幅值（pu）
                              uint64_t         triggerTimeMs,    // 触发时间（毫秒）
                              int              phase);
int transfer_json_qvvr_data(const std::string& dev_id, ushort monitor_id,
                            double mag, double dur, long long start_tm, int dis_kind,int phase,
                            const std::string& wavepath);
//录波文件上传接口
void SOEFileWeb(std::string& localpath,std::string& cloudpath, std::string& wavepath);

//录波文件目录接口
bool assign_qvvr_file_list(const std::string& id, ushort nCpuNo, const std::vector<std::string>& file_list_raw);

//录波文件下载完成通知接口
bool update_qvvr_file_download(const std::string& filename_with_mac, const std::string& terminal_id);

//上送文件列表接口
bool send_file_list(terminal_dev* dev, const std::vector<tag_dir_info> &FileList);

//提取mac
std::string normalize_mac(const std::string& mac);

//暂态文件超时检测
void check_and_backup_qvvr_files();

//业务超时检查
void check_device_busy_timeout();

//业务上报
void send_reply_to_cloud(int reply_code, const std::string& dev_id, int type, const std::string& guid, const std::string& mac);
void send_batch_reply_to_queue(const std::string& guid,
                                      const std::vector<DeviceReply>& replies);

//内部定值响应
bool send_internal_value_reply(const std::string &dev_id, const std::vector<DZ_kzz_bit> &control_words);

//定值响应
bool send_set_value_reply(const std::string &dev_id, unsigned char mp_index, const std::vector<DZ_TAB_STRUCT> &dz_info);

//保存内部定值描述
bool save_internal_info(const std::string &dev_id, const std::vector<NameFixValue> &fixValueList);

//保存内部定值数值
bool save_internal_value(const std::string &dev_id, const std::vector<ushort> &fabsf);

//保存定值数值
bool save_set_value(const std::string &dev_id, unsigned char mp_index, const std::vector<float> &fabsf);

//发送文件
void SendFileWeb(const std::string& strUrl, const std::string& localpath, const std::string& cloudpath, std::string& wavepath);

//状态翻转
void connect_status_update(const std::string& id, int status);


//业务响应
void on_device_response_minimal(int response_code,
                                const std::string& id,
                                unsigned char cid,
                                int device_state_int);

//找监测点id
bool get_monitor_id_by_dev_and_seq(const std::string& terminal_id,
                                   unsigned short logical_seq,
                                   std::string& out_monitor_id);
bool get_monitor_name_by_monitor_id(const std::string& monitor_id,
                                    std::string& out_monitor_name);
bool get_terminal_name_by_terminal_id(const std::string& terminal_id,
                                      std::string& out_terminal_name);                                    


//处理补招的任务
void check_recall_event();
void check_recall_file();

//补招响应
void send_reply_to_kafka_recall(const std::string& guid, int step,int code, const std::string& result,const std::string& terminalId,const std::string& lineIndex,const std::string& recallStartDate,const std::string& recallEndDate);

//缓存目录信息
void filemenu_cache_put(const std::string& dev_id,
                        std::vector<tag_dir_info> FileList);
//提取目录信息
bool filemenu_cache_take(const std::string& dev_id, std::vector<tag_dir_info>& out);

//清空装置台账
size_t erase_one_terminals_by_id(const std::string& terminal_id);

//转换结构
DeviceInfo make_device_from_terminal(const terminal_dev& t);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////模板打印
// ===== 通用打印实现（模板） =====

template <typename Mon>
inline void print_monitor_common(const Mon& mon) {
    auto safe = [](const std::string& s) -> const std::string& {
        static const std::string NA = "N/A";
        return s.empty() ? NA : s;
    };

    std::cout << "Monitor ID: "               << safe(mon.monitor_id)         << "\n";
    std::cout << "Terminal ID: "              << safe(mon.terminal_id)        << "\n";
    std::cout << "Monitor Name: "             << safe(mon.monitor_name)       << "\n";
    std::cout << "Logical Device Sequence: "  << safe(mon.logical_device_seq) << "\n";
    std::cout << "Voltage Level: "            << safe(mon.voltage_level)      << "\n";
    std::cout << "Terminal Connect: "         << safe(mon.terminal_connect)   << "\n";
    std::cout << "Timestamp: "                << safe(mon.timestamp)          << "\n";
    std::cout << "Status: "                   << safe(mon.status)             << "\n";
    std::cout << "CT1: " << mon.CT1 << "\n";
    std::cout << "CT2: " << mon.CT2 << "\n";
    std::cout << "PT1: " << mon.PT1 << "\n";
    std::cout << "PT2: " << mon.PT2 << "\n";
}

template <typename Dev>
inline void print_terminal_common(const Dev& tmnl) {
    auto safe = [](const std::string& s) -> const std::string& {
        static const std::string NA = "N/A";
        return s.empty() ? NA : s;
    };

    std::cout << "GUID: "             << safe(tmnl.guid)          << "\n";
    std::cout << "Terminal ID: "      << safe(tmnl.terminal_id)   << "\n";
    std::cout << "Terminal Code: "    << safe(tmnl.terminal_name) << "\n";
    std::cout << "Organization Name: "<< safe(tmnl.org_name)      << "\n";
    std::cout << "Maintenance Name: " << safe(tmnl.maint_name)    << "\n";
    std::cout << "Station Name: "     << safe(tmnl.station_name)  << "\n";
    std::cout << "Factory Name: "     << safe(tmnl.tmnl_factory)  << "\n";
    std::cout << "Terminal Status: "  << safe(tmnl.tmnl_status)   << "\n";
    std::cout << "Device Type: "      << safe(tmnl.dev_type)      << "\n";
    std::cout << "Device Key: "       << safe(tmnl.dev_key)       << "\n";
    std::cout << "Device Series: "    << safe(tmnl.dev_series)    << "\n";
    std::cout << "Address: "          << safe(tmnl.addr_str)      << "\n";
    std::cout << "Port: "             << safe(tmnl.port)          << "\n";
    std::cout << "Timestamp: "        << safe(tmnl.timestamp)     << "\n";
    std::cout << "Righttime: "        << safe(tmnl.Righttime)     << "\n";
    std::cout << "mac: "              << safe(tmnl.mac)           << "\n";

    // 安全遍历最多前 10 个测点（不越界），且跳过空 monitor_id 的项
    const size_t n = std::min<size_t>(tmnl.line.size(), 10);
    for (size_t i = 0; i < n; ++i) {
        if (tmnl.line[i].monitor_id.empty()) continue;
        std::cout << "  Monitor " << (i + 1) << ":\n";
        print_monitor_common(tmnl.line[i]);  // 模板会自动匹配 update/ledger 的 monitor
    }
}

// ===== 薄包装重载（保持原有函数名不变）=====

inline void print_monitor(const update_monitor& mon) { print_monitor_common(mon); }
inline void print_monitor(const ledger_monitor& mon) { print_monitor_common(mon); }

inline void print_terminal(const update_dev& tmnl) { print_terminal_common(tmnl); }
inline void print_terminal(const terminal_dev& tmnl) { print_terminal_common(tmnl); }

///////////////////////////////////////////////////////////////////////////////////////////////////////////////小工具
// 小工具：判断 s 是否以 suffix 结尾
inline bool has_suffix(const std::string& s, const std::string& suffix) {
    if (suffix.size() > s.size()) return false;
    return std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
}

// 小工具：替换前缀
inline bool replace_prefix(std::string& s, const std::string& from, const std::string& to) {
    if (s.rfind(from, 0) == 0) { // 以 from 为前缀
        s.replace(0, from.size(), to);
        return true;
    }
    return false;
}

inline std::string trim_cstr(const char* s, size_t n) {
    if (!s) return {};
    size_t end = 0;
    while (end < n && s[end] != '\0') ++end;
    std::string out(s, s + end);
    while (!out.empty() && (out.back() == ' ' || out.back() == '\t' || out.back() == '\r' || out.back() == '\n'))
        out.pop_back();
    return out;
}

// 去首尾空格
inline std::string trim_copy(const std::string& s) {
    size_t b = s.find_first_not_of(" \t\r\n");
    if (b == std::string::npos) return "";
    size_t e = s.find_last_not_of(" \t\r\n");
    return s.substr(b, e - b + 1);
}

//清洗字符串
inline std::string sanitize(std::string s) {
    // 截断第一个 NUL 及其后内容
    size_t z = s.find('\0');
    if (z != std::string::npos) s.erase(z);
    // 去掉尾部不可打印字符（含 \r \n 等）
    while (!s.empty()) {
        unsigned char c = static_cast<unsigned char>(s.back());
        if (c >= 32 && c != 127) break;
        s.pop_back();
    }
    return s;
}

// 当前本地时间，格式 "YYYY-MM-DD HH:MM:SS"
inline std::string now_yyyy_mm_dd_hh_mm_ss() {
    std::time_t t = std::time(nullptr);
    std::tm tmv;
#if defined(_WIN32)
    localtime_s(&tmv, &t);   // Windows 线程安全
#else
    localtime_r(&t, &tmv);   // POSIX 线程安全
#endif
    std::ostringstream oss;
    oss << std::put_time(&tmv, "%Y-%m-%d %H:%M:%S");
    return oss.str();
}

// 简单键值提取（兼容半角/全角冒号）
inline bool parse_kv_line(const std::string& line,
                                 const std::string& key,
                                 std::string& out) {
    std::string k1 = key + ":";
    std::string k2 = key + "：";
    if (line.compare(0, k1.size(), k1) == 0) {
        out = trim_copy(line.substr(k1.size()));
        return true;
    } else if (line.compare(0, k2.size(), k2) == 0) {
        out = trim_copy(line.substr(k2.size()));
        return true;
    }
    return false;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////实时数据用
// === 专用锁 + 数据表（仅管实时 idx 映射） ===
extern std::mutex devidx_lock;                        // 新锁（不要用 ledgermtx）
extern std::unordered_map<std::string,int> devIdxMap; // id -> idx，一对一

// === 常用操作：全部用这把锁保护 ===
inline void devidx_set(const std::string& id, int idx) {
    std::lock_guard<std::mutex> lk(devidx_lock);
    devIdxMap[id] = idx;                // 覆盖更新
}

inline bool devidx_get(const std::string& id, int& out_idx) {
    std::lock_guard<std::mutex> lk(devidx_lock);
    auto it = devIdxMap.find(id);
    if (it == devIdxMap.end()) return false;
    out_idx = it->second;
    return true;
}

void enqueue_realtime_pq(const RealtagPqDate_float& realdata,
                         int nPTType,
                         unsigned char cid,
                         const std::string& mac,
                         const std::string& devid);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////统计数据
void enqueue_stat_pq(const std::string& max_base64Str,
                     const std::string& min_base64Str,
                     const std::string& avg_base64Str,
                     const std::string& cp95_base64Str,
                     time_t data_time,
                     const std::string& mac,
                     short cid);

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
extern int g_front_seg_index;
extern std::string FRONT_INST;
extern std::string FRONT_PATH;
extern std::string WEB_FILEUPLOAD;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 云平台响应码枚举
enum class ResponseCode : int {
    OK                = 200, // 请求成功
    ACCEPTED          = 201, // 请求被接受，开始处理
    PROCESSING        = 202, // 请求被接受，但是未处理完
    BAD_REQUEST       = 400, // 请求失败
    UNAUTHORIZED      = 401, // 请求未认证/认证错误（不支持的请求）
    REJECTED_BUSY     = 402, // 请求被拒绝，在处理同类命令
    FORBIDDEN         = 403, // 请求被拒绝（未知原因）
    NOT_FOUND         = 404, // 请求的资源不存在
    BUSY              = 405, // 当前忙，无法响应
    TIMEOUT           = 406, // 请求超出了等待时间
    INTERNAL_ERROR    = 500  // 其他错误
};

inline std::string ResponseCodeToString(int code) {
    switch (code) {
        case 200: return "请求成功";
        case 201: return "请求被接受，开始处理";
        case 202: return "请求处理中";
        case 400: return "请求失败，参数错误";
        case 401: return "未认证或认证错误";
        case 402: return "请求被拒绝：正在处理同类命令";
        case 403: return "请求被拒绝";
        case 404: return "资源不存在";
        case 405: return "当前忙，无法响应";
        case 406: return "请求超时";
        case 500: return "内部错误";
        default:  return "未知响应码";
    }
}

static inline bool is_ok(int rc) { return rc == static_cast<int>(ResponseCode::OK); }

static bool parse_datetime_tm(const std::string& s, std::tm& out) {
    std::memset(&out, 0, sizeof(out));
    return strptime(s.c_str(), "%Y-%m-%d %H:%M:%S", &out) != nullptr;
}
#endif

/////////////////////////////////////////////////////////////////////////////补招文件记录
// 记录 (guid, monitorId) -> 文件完整路径
extern std::mutex g_recall_file_mtx;
extern std::map<std::pair<std::string,std::string>, std::string> g_recall_file_index;

// 初始化 / 追加 / 删除
bool init_recall_record_file(const std::string& guid,
                             const std::string& terminalId,
                             const std::string& monitorId,
                             const std::string& start,
                             const std::string& end);

bool append_recall_record_line(const std::string& guid,
                               const std::string& monitorId,
                               const std::string& msg);

bool delete_recall_record_file(const std::string& guid,
                               const std::string& monitorId);

bool get_recall_record_fields_by_guid_monitor(const std::string& guid,
                                              const std::string& monitorId,
                                              std::string& outGuid,
                                              std::string& terminalId,
                                              std::string& outMonitorId,
                                              std::string& startTime,
                                              std::string& endTime,
                                              std::string& msg);

bool SendFileWebAuto(const std::string& id,
                     const std::string& local_path,
                     const std::string& remote_path,
                     std::string& out_filename);

void cleanup_old_unpaired_qvvr_events();