#ifndef SCHEDULE_HPP_
#define SCHEDULE_HPP_

#include <iostream>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include <stdint.h>
#include <boost/container/detail/singleton.hpp>
#include "upgrade_cfg.hpp"
#include "status_mgr.hpp"

#define SCHEDULE_CONFIG "/opt/configenv/schedule.json"
#define DEBUG_SCHEDULE_CONFIG "/opt/configenv/debug_schedule.json"
#define UPGRADE_SCHEDULE_CONFIG "/opt/configenv/upgrade_schedule.json"
#define TRIGGER_WAVE_CONFIG "/opt/configenv/trigger_wave.json"

typedef enum {
    kScheduleResultNone = 0,
    kScheduleUnknownSensor = 1,
    kScheduleConfigSensor = 2,
    kScheduleEigenValue = 3,
    kScheduleWaveForm = 4,    
    kScheduleUpgrade = 5,
    kScheduleWrongTime = 6
} ScheduleResult;

typedef enum {
    kUpgradeSuccess = 0, // 成功
    kProductTypeMismatch = 1, // 包有问题，不再重试
    kZigbeeHWMismatch = 2, // 包有问题，不再重试
    kTransmitFileCrcError = 3, // 此返回值时，要重试
    kRecvDataLenError = 4, // 此返回值时，要重试
    kUpgradeDoneBefore = 5 // 当前就是这个版本，不需要升级了
} FirmFileCheckResult;

typedef struct {
    uint16_t short_addr;
    std::string sensor_type;
    int hw_version;
    std::string current_sw_version;
    std::string upgrade_sw_version;
} UpgradeParameter;

class SensorScheduler {
public:
    SensorScheduler();    

    void SetScheduleStatus(ScheduleStatus status);
    ScheduleStatus GetScheduleStatus();
    // kScheduleConfigSensor  kScheduleUpgrade 等有结果，调我接口通知结果
    // kScheduleEigenValue kScheduleWaveForm
    // 上面4个结束，调GetNextDuration()获取休眠时间
    // 如果是kScheduleWrongTime, 此函数next_duration表明休眠时间
    int StartSchedule(uint16_t short_addr, int &next_duration, bool &z, int &next_task_id);
    int GetNextDuration(uint16_t short_addr, bool &z, int &next_task_id);
    /**
     * @brief 
     * 
     * @param short_addr 
     * @param z 如果需要触发z轴波形，此参数为1, 否则为0
     * @param xy 如果需要触发xy轴波形，此参数为1, 否则为0     
     */
    int TriggerWave(uint16_t short_addr, uint8_t z, uint8_t xy);

    // z用于说明是z轴波形，还是xy轴波形
    int WaveError(uint16_t short_addr, bool z);    
    void WaveSuccess(uint16_t short_addr, bool z);
    // long GetBaseTimestamp(int id);
    long CalcNextTimestamp(int id, uint16_t short_addr, bool &z, int& next_task_id);

    // 当有传感器需要更新配置时调用
    int UpdateSensorConfig(uint16_t short_addr);
    // 当更新结束后，调用此接口，result为0是成功，其它值为失败
    int UpdateConfigResult(uint16_t short_addr, int result);

    int Config(int eigen_value_send_interval, int wave_form_send_interval,               
               int &max_sensor_num, int wave_resend_num, std::string &error_msg);

    int CalcAvailableSlice(int eigen_value_send_interval, int wave_form_send_interval,                           
                           int &max_sensor_num, int &available_slice, int &free_slice,
                           std::string &error_msg);
    
    int GetScheduleConfig(int &eigen_value_send_interval, int &wave_form_send_interval, int &wave_resend_num,                          
                           int &max_sensor_num);
    // ======schedule.json操作开始======
    // 无线网关程序重启时
    // void ReadScheduleCfg();
    // 配置完成后
    int WriteScheduleCfg(long &ts, std::string &world_time);

    // 当系统进行校时时，输入参数为新的时间戳与以前时间戳的差值
    void ModifyScheduleTs(int diff_ts);

    // 当接入传感器时，设置为不可修改; 当停用所有传感器后，修改为可修改
    // void AdjustSupportModification(bool support_modification);    
    // ======schedule.json操作结束======

    void ClearScheduleCfg(uint16_t short_addr = 0);

    long GetLocalTs();
    long GetLocalWorldTime(std::string &world_time);
    std::string GetUTCTime(long ts);
    int GetAvailableId(uint16_t short_addr);

    // 调试模式相关接口
    // 此接口可多次调用，但是总是以最后一次调用为准
    int OpenDebugMode(std::vector<uint16_t> short_addr_list);
    int CloseDebugMode();

    // 升级模式相关接口    
    /**
     * @brief 当有传感器需要升级时调用, 此接口也会打开升级模式，可重复调用
     * sensor_type: DN101, DN102
     * hw_version: 3, 4
     * current_sw_version: 1.1
     * upgrade_sw_version: 1.2    
     */
    int UpgradeSensor(std::vector<UpgradeParameter> &param_list);
    int CancelUpgradeSensor(std::vector<uint16_t> short_addr_list);
    int CloseUpgradeMode();
    /**
     * @brief 升级后，无线传感器发回来的返回值
     * 
     * @param short_addr 
     * @param result 参考：FirmFileCheckResult
     * 返回值表明操作是否成功，0成功，其它失败
     */
    int UpgradeResult(uint16_t short_addr, int result);

private:
    void UpdateUpgradeInfo(int id);
    void CleanIdleOccupiedSet(long ts);
    void UseDefaultConfig();
    int GetDebugUpgradeNextDuration(uint16_t short_addr);
    long GetDebugUpgradeNextTS(uint16_t short_addr);

    // user config
    int eigen_value_send_interval_;
    int eigen_value_send_duration_;
    int wave_form_send_interval_;
    int wave_form_send_duration_;
    int max_sensor_num_;   
    int wave_resend_num_;

    // calc result
    long start_timestamp_;
    std::string start_ts_str_;
    int available_slice_;
    int free_slice_;
    int wave_slice_num_per_eigen_interval_; // 每个特征值窗口中有几个波形发送窗口
    int seconds_per_wave_slice_; // 波形窗口时长
    int eigen_value_slice_total_seconds_; // 特征值窗口总时长
    int *slice_sensor_id_; // 每个时间窗是哪个传感器使用的
    uint8_t *slice_is_z_wave_; // 表明此窗口是z轴波形还是xy的
    std::unordered_map<int, std::pair<int,int>> sensor_id_nth_slice_; // 传感器编号与z,xy波形发送窗口对应关系
    std::map<uint16_t, int> short_addr_map_; // base_relation.json

    // 存储当前2小时内失败与成功的传感器
    std::map<uint16_t, int> z_failure_map_;
    std::map<uint16_t, int> xy_failure_map_;
    std::unordered_set<uint16_t> z_success_set_;
    std::unordered_set<uint16_t> xy_success_set_;
    std::unordered_set<uint16_t> z_patch_set_; // 漏传的补传    
    std::unordered_set<uint16_t> xy_patch_set_; // 漏传的补传
    void ClearFailureSuccessMap();
    bool ZRetransferWave(uint16_t short_addr);
    bool ZMissedWave(uint16_t short_addr);
    bool XYRetransferWave(uint16_t short_addr);
    bool XYMissedWave(uint16_t short_addr);    

    // 空闲时间戳被占用
    std::unordered_set<long> free_slice_ocuppied_;

    // sensor config update
    std::unordered_set<int> update_;

    // sensor upgrade
    std::map<int, UpgradeInfo> upgrade_;

    // temp variables
    long current_ts_;  // 当前时间戳
    long current_wave_start_ts_; // 当前所在的波形发送间隔的开始时间戳
    long nth_wave_start_slice_; // 第几个波形发送窗口
    long seconds_in_current_wave_slice_; // 时间戳相对波形开始时间戳的秒数
    int nth_eigen_value_slice_; // 第几个特征值发送窗口
    int seconds_in_current_eigen_slice_; // 相对特征值发送间隔的秒数
    bool ts_in_eigen_slice_; // 时间位于特征值发送窗口中
    int nth_eigen_slice_; // 如果ts_in_eigen_slice_是真的话，此值表明是第几个特征值窗口
    int nth_wave_slice_; // 如果ts_in_eigen_slice_是假的话，此值表明是第几个波形窗口

    int current_request_;
    ScheduleStatus current_schedule_status_;
    

    // debug mode
    std::map<int, int> debug_sensor_id_nth_slice_; // 调度模式下传感器编号与z波形发送窗口对应关系
    uint16_t *debug_slice_sensor_id_; // 每个时间窗是哪个传感器使用的
    // std::vector<int> debug_short_addr_list_;
    std::unordered_set<uint16_t> debug_list_;
    void GenerateDebugSchedule(std::vector<uint16_t> short_addr_list);

    // upgrade mode
    std::map<int, int> upgrade_sensor_id_nth_slice_; // 升级模式下传感器编号与升级发送窗口对应关系
    std::unordered_set<uint16_t> upgrade_list_;
    uint16_t *upgrade_slice_sensor_id_; // 每个时间窗是哪个传感器使用的
    void GenerateUpgradeSchedule();

    std::map<uint16_t, std::pair<uint8_t, uint8_t>> trigger_wave_record_;
    void WriteTriggerWaveRecord();
    void ReadTriggerWaveRecord();
};

typedef boost::container::dtl::singleton_default<SensorScheduler> scheduler;

#endif // SCHEDULE_HPP_