//
// Created by WJG on 2020-7-7.
//

#ifndef NEWCOSS_SCENEMANAGER_H
#define NEWCOSS_SCENEMANAGER_H

#include <string>
#include <unordered_map>
#include <unordered_set>
#include <mutex>
#include "json/json.h"
#include "scene_comm.h"
#include "TimerWorker.h"
#include "SceneThreadPool.h"
#include <jebase/config.h>
#include <qlibc/QPObjectHolder.h>

class JE_API SceneWorkHandler {
public:
     virtual void cancelSceneRunning() = 0;
};

class JE_API RunningScene {
protected:
    std::string id_;
    std::string name_;
    SceneWorkHandler* worker_;
public:
    explicit RunningScene(std::string id, std::string name, SceneWorkHandler* worker) :
        id_(std::move(id)), name_(std::move(name)), worker_(worker) {
    }

    SceneWorkHandler* getSceneWorker() {
        return worker_;
    }
};

struct SceneFeature_T {
    std::string scene_id;
    std::string scene_name;
    std::string scene_status;    //该场景状态。 disable - 未启用； enable - 已启用
    std::string scene_describe;   //规则描述
    std::string scene_type;      //场景类别：customise - 用户自定义; recommend - 推荐
    std::string run_type;        //场景执行方式。auto - 自动执行， manual - 手动执行
    std::string run_day;        //当repeat_condition字段为4时，取值0~6，星期天为0；如星期二/星期五执行，则数据为字符串"25".
    int familyId;               //家庭
    std::string backgroundUri;   //背景图片
    Json::UInt64 update_time;
    int repeat_condition;  //复规则:0-单次;1-工作日;2-周末;3-每天;4-自定义
    Json::Value scene_trigger;
    Json::Value scene_rules;
    unsigned long last_active_time;
};

class SceneManager {
public:
    static SceneManager& GetInstance()
    {
        if(m_pInstance == nullptr)
            m_pInstance = new SceneManager();
        return *m_pInstance;
    };

    ~SceneManager();

    std::string scene_file_path;
    std::string scene_file_path_init;

    int initScenePool(const std::string &path, const std::string& init_dir);
    int reloadScenePool();
    int reloadScene(const std::string &scene_id);
    std::unordered_set<std::string> getScenebyTrigger(const std::string &trigger);
    Json::Value getEnableSceneRule(const std::string &scene_id);
    Json::Value getSceneRule(const std::string &scene_id);
    int getSceneCount();
    int enableScene(const std::string &scene_id);
    int disableScene(const std::string &scene_id);
    int activeScene(const std::string& from, std::string &scene_id);
    int activeScenebyName(std::string &scene_name);
    int activeScenebyExternal(std::string &scene_name);
    Json::Value getSceneInfo();
    Json::Value getSceneInfo(const std::string &scene_id);
//    Json::Value getSceneContent();
    Json::Value getSceneContent(const std::string &scene_id);
//    int setShortcutScene(const Json::Value &scene);
//    Json::Value getShortcutSceneInfo();
//    int delShortcutScene(const Json::Value &scene_id);

    //针对Light+场景的处理
    int addLightjiaScene(Json::Value &data);
    int deleteLightjiaScene(std::string &scene_id);

    // forceNoGroup: 是否强制不进行智能分组尝试，清理分组时使用
    int parseLightjiaScene(const std::string &scene_id, bool forceNoGroup = false);
    //分组加速
    int regroupLightjiaScene(const std::string &scene_id);
    //清理分组加速
    int clearGroupInLightjiaScene(const std::string &scene_id);

    bool hasSceneRunning();
    bool setSceneRunning(const std::string &id, const std::string &name, SceneWorkHandler *pWorker);
    void setSceneQuitting(const std::string& id);
    int putScene2Queue(const Json::Value& scene_job);
    int runScene(const Json::Value &data);
    int removeScene(const std::string &scene_id);

    int editLinkage(const std::string &scene_id, const std::string &pad_sn, const std::string &pad_accept);
    int cleanLinkage(const std::string &scene_id);
    Json::Value getLinkage(const std::string &scene_id);
    int cleanUserScene();
//    int deleteUserScene(const std::string &scene_id);
    std::unordered_set<std::string> checkUserScene(std::unordered_set<std::string> cloud_id_set);
    std::unordered_set<std::string> getUserScene();

    static bool checkSceneRunning(SceneFeature_T& sc);

    bool isDefaultScene(const std::string &sceneId);

    void setDefaultScene(const std::string &sceneId);

    void getOriginalSceneContent(const std::string &scene_id, Json::Value &scene);

    int stopSceneTimerWorker(const std::string &scene_id);
    bool addSceneTimerWorker(const std::string &scene_id, TimerWorker *tWorker);

private:
    static SceneManager* m_pInstance;
    SceneManager();
    int enable_number;
    int disable_number;

    std::string default_light_scene_id;
    std::unordered_map<std::string, SceneFeature_T> scene_pool;
    std::unordered_map<std::string, SceneFeature_T> enableScene_pool;
    std::unordered_map<std::string, SceneFeature_T> disableScene_pool;
    std::recursive_mutex scene_mutex;
    std::unordered_map<std::string, std::unordered_set<std::string>> device_data_trigger;  //<trigger, scene_id>
    std::unordered_map<std::string, std::unordered_set<std::string>> app_cmd_trigger;  //<trigger, scene_id>
//    std::unordered_map<std::string, std::unordered_set<std::string>> system_cmd_trigger;
    std::unordered_map<std::string, std::unordered_set<std::string>> system_timer_trigger;

    int creatScenePool();
    int parseSceneFile(const std::string& fname);
    int parseDefaultSceneFile(const std::string& fname);

    SceneThreadPool* sThreadPool;
    TimerWorker *timerWorker;
    std::unordered_map<std::string, std::string> sceneIdTimeMap;   //<id, updateTime>
    std::mutex sceneIdTime_mutex;
//    void defalutSubscribeLight(Json::Value actions);
    Json::Value linkage_sceneid_json;
    std::unordered_set<std::string> user_scene_id_set;

    //用一个map记录已经在跑的场景
    qlibc::QPObjectHolder<RunningScene> mRunningScenes;

    //记录场景id对应的在跑的Timer
    std::unordered_map<std::string, std::list<TimerWorker *>> mTimerMap;
    std::list<TimerWorker *> mDelTimerList;
    std::mutex _timer_mutex;

    //add or modify by hutao.
    bool quit_scene_ = false;
    short showType = 0;

#if 1 //defined(DEBUG)
    short showCount = 0;
    static const short showCountPoint = 5;
#endif
    //add by hutao , 2022.06.03
public:
    void triggerMultiPanelScene(const std::string &scene_id, const std::string &msg);

protected:
    void addTriggertoPool(std::unordered_map<std::string, std::unordered_set<std::string>> &tirggerMap,
                          const std::string &trigger, const std::string& sceneId);

    void loadSceneTriggers(const SceneFeature_T &sceneData);

    void loadTrigger(const std::string& trigger, const std::string& scendId);

    void showLoadedScenesAndTriggers(short udType = -1);

    void removeTriggers(SceneFeature_T &sceneT);

};


#endif //NEWCOSS_SCENEMANAGER_H
