#ifndef DBTREEVIEWMANAGER_H
#define DBTREEVIEWMANAGER_H
#define NOMINMAX

#include <QWidget>
#include <QTreeView>
#include <QJsonObject>
#include <QStandardItemModel>
#include <QCheckBox>
#include <QJsonArray>
#include <QFile>
#include <QLineEdit>
#include <QComboBox>
#include <QRadioButton>
#include <QButtonGroup>
#include <QStyleFactory>
#include <QEvent>
#include <QStringList>
#include <QSettings>
#include <QSet>
#include <QVariant>
#include <QMenu>
#include <QAction>
#include <QTimeEdit>
#include <QCursor>
#include <QScrollArea>
#include <QToolButton>
#include <QtSql>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QMessageBox>
#include <QPainter>
#include <QTimer>
#include <QFileInfo>
#include <QLabel>
#include <QHBoxLayout>
#include <QPushButton>
#include <QVBoxLayout>
#include <QStandardItem>
#include <QMap>
#include <QJsonDocument>
#include <array>
#include "CViewInterface.h"
#include "Src/Sql/SqlOperation.h"
#include "gen_interface.h"

// 组合控件
struct ST_COMBINED_CONT
{
    QString strConfigurationsName;//configurations.db 里面的名称
    QString strfieldName;
    QString strfieldDescribe;

    QLineEdit* pLineC;
    QPushButton* pGetBut;
    QPushButton* pSetBut;
};

struct ST_INPUT_CONT
{
    QString strConfigurationsName;
    QString strfieldName;
    QString strfieldDescribe;

    QLineEdit* plineEdit;
};

struct ST_RADIO_CONT
{
    QString strConfigurationsName;
    QString strfieldName;
    QString strfieldDescribe;

    QButtonGroup* pradioGroup;
};

struct ST_CHECKBOX_CONT
{
    QString strConfigurationsName;
    QString strfieldName;
    QString strfieldDescribe;

    QCheckBox* pcheckBox;
};

struct ST_COMBOBOX_CONT
{
    QString strConfigurationsName;
    QString strfieldName;
    QString strfieldDescribe;

    QComboBox* pcomboBox;
};

struct ST_TIME_CONT
{
    QString strConfigurationsName;
    QString strfieldName;
    QString strfieldDescribe;

    QTimeEdit* ptimeEdit;
};

struct ST_SWITCH_CONT
{
    QString strConfigurationsName;
    QString strfieldName;
    QString strfieldDescribe;

    QCheckBox* pswitchBox;
};

class OriginalWnd;

/**
 * @class DbTreeViewManager
 * @brief 管理树状视图、导航栏、以及与数据库交互的相关逻辑。
 *
 * 该类负责从数据库加载目录树 ,并根据用户权限和配置 ID 显示相应的字段与控件。
 * 同时还支持切换 Home 界面或其他配置界面、隐藏/显示按钮与分隔线等功能。
 */
class DbTreeViewManager : public QWidget
{
    Q_OBJECT

public:
    /**
     * @brief 构造函数
     * @param originalWnd  指向 OriginalWnd 对象的指针
     * @param widget2      另一个父级或容器部件,用于添加子控件
     * @param parent       父窗口指针,可为空
     */
    explicit DbTreeViewManager(QWidget* pOriginalWndMenuPage, QWidget* parent = nullptr);
    ~DbTreeViewManager();


    /**构造初始化
     */
    void Init();

    /**
     * @brief 初始化目录树,从数据库加载数据
     * @param name       一级目录名字,对应数据库中的 Configurations 表
     * @param userPrivilege  当前用户的权限等级
     */
    void initializeTree(QString name, const int &userPrivilege);

    /**
     * @brief 清理所有分隔线(内部调用,用于清除旧有的一级目录分隔线等)
     */
    void clearAllSeparators();

    /**
     * @brief 收集所有第三层目录的 QStandardItem
     * @return 包含第三层目录项的列表
     */
    QList<QStandardItem*> collectAllThirdLevelItems();

    /**
     * @brief 保存所有当前已展开的路径
     *   对应 expandedPaths 中的路径保存到持久化存储(如 QSettings)
     */
    void saveExpandedPaths();

    /**
     * @brief 加载已展开的路径
     *   从持久化存储(如 QSettings)中读取展开路径并恢复
     */
    void loadExpandedPaths();

    /**
     * @brief 将日志写入文件中
     *
     */
    void writeLogToFile(const QString& logMessage, const QString& filePath);

    void loginput(const QString& fieldTableName,const QString& fieldName,const QString& modifies);

    /**
     * @brief 存储已展开路径的容器
     *   格式通常为 "Root/Child/Child" 的字符串
     */
    QSet<QString> expandedPaths;

public:
    struct menuInfo {
        int menuId;
        bool isthird;
        int  index;

    };
    int currentMenuId;
    std::array<menuInfo, 5> menuArray;
    void loadpage(const int& configId);
    QList<QStandardItem*> thirdLevelListtest;
    QStandardItem* deepCopyItem(const QStandardItem* item);
    void promptSaveChanges();
signals:
    void RunFunSignals(ns_module::ST_BUTTON_FUN pra);
    void saveClicked();


private slots:

    /**
     * @brief 当树中某个项目被点击时触发
     * @param index 被点击的 QModelIndex
     */
    void onTreeViewClicked(const QModelIndex &index);

    /**
     * @brief 当树中某个项目被点击时触发,专门给up和down按钮使用
     * @param index 被点击的 QModelIndex
     */
    void onTreeViewClicked_updown(const QModelIndex &index);
    /**
     * @brief “返回”按钮点击槽函数
     *   用于在第三层目录与上层目录间进行返回逻辑
     */
    void onButtonBackClicked();

    /**
     * @brief “上”按钮点击槽函数
     *   用于在所有第三层目录间向上移动
     */
    void onButtonUpClicked();

    /**
     * @brief “下”按钮点击槽函数
     *   用于在所有第三层目录间向下移动
     */
    void onButtonDownClicked();

    /**
     * @brief “左”按钮点击槽函数
     *   用于目录层级的向左逻辑(如果有需要)
     */
    void onButtonLeftClicked();

    /**
     * @brief “右”按钮点击槽函数
     *   用于目录层级的向右逻辑(如果有需要)
     */
    void onButtonRightClicked();

    /**
     * @brief 当树状模型中某个 QStandardItem 的复选框状态发生变化时触发
     * @param item 发生变化的 QStandardItem
     */
    void onItemChanged(QStandardItem *item);

private:
    /**三级菜单独的保存按钮
     */
    void Level3MenuAllSaveBut(QVBoxLayout* pVBox);

private:
    /**OriginalWnd 窗口
     */
    OriginalWnd* m_originalWnd = nullptr;

    /** 主菜单页面,显示功能
     */
    QWidget * m_pOriginalWndMenuPage = nullptr;

    /**
     * @brief 树视图控件
     */
    QPointer<QTreeView>     m_pTreeViewDown;

    /**
     * @brief 导航栏 QWidget,用于显示路径信息
     */
    QPointer<QWidget>      m_pNavigationWidget;

    /**
     * @brief 树状模型,用于存放目录层级
     */
    QPointer<QStandardItemModel> m_pCModel = nullptr;

    /**
     * @brief 用于存储第三层字段展示窗口的指针(单实例)
     */
    QWidget* m_thirdLevelFieldWnd = nullptr;

    /**
     * @brief 上部的几个操作按钮(例如 “返回”、“上”、“下”、“左”、“右”)
     */
    QPushButton *ButtonBack = nullptr;       ///< 返回按钮
    QPushButton *buttonUp = nullptr;        ///< 上按钮
    QPushButton *buttonDown = nullptr;      ///< 下按钮
    QPushButton *buttonLeft = nullptr;      ///< 左按钮
    QPushButton *buttonRight = nullptr;     ///< 右按钮




    //  定义一个结构来记录当前所处页面的信息
    struct PageState {
        QStringList path;    // 记录目录的文本路径
        bool isThirdLevel;   // 是否是第三层目录
        int  directoryId;    // 第三层目录ID
        QString multiTableName = "";
    };


    //  存储“后退栈”和“前进栈”,
    QList<PageState> m_backStack;
    QList<PageState> m_forwardStack;

    /**
    * @brief restoring 标记是否在恢复阶段
    */
    bool m_isRestoring = false;

    /**
     * @brief 存储“一级目录”和相应分隔线的映射,用于更新和控制分隔线位置、可见性等
     */
    QMap<QStandardItem*, QFrame*> m_mapFirstLevelSeparators;

    /**
     * @brief 标记是否阻止触发 onItemChanged 等复选框变更响应
     */
    bool m_blockItemChanged = false;

    /**
     * @brief  用于存储第三层界面生成的控件列表,方便统一管理和销毁
     */
    QList<QWidget*> m_fieldWidgets;


    /**
     * @brief  当前正在使用的配置名字  ????
     */
    QString m_currentConfigName = "";

   // int m_currentConfigId = -1;
    /**
     * @brief  特定分隔线,Home 界面时隐藏,其他界面时显示
     */
    QPointer<QFrame>     m_pLineFrame1;

    /**数据库存储
     */
    SqlOperation* m_sqlOper = nullptr;
    
    /**组合控件
     */
    std::vector<ST_COMBINED_CONT> m_veCombinedCont;
    std::vector<ST_INPUT_CONT> m_veInputCont;
    std::vector<ST_RADIO_CONT> m_veRadioCont;
    std::vector<ST_CHECKBOX_CONT> m_veCheckBoxCont;
    std::vector<ST_COMBOBOX_CONT> m_veComboBoxCont;
    std::vector<ST_TIME_CONT> m_veTimeCont;
    std::vector<ST_SWITCH_CONT> m_veSwitchCont;
    ns_module::CViewInterface* m_pTreeCViewInterface;

    /**二级表目录的名称
     */
    QString m_str2DirModuleType;

    QSet<QLabel*> modifiedLabels;

    //字段展示 m_clear 替换
    const QString m_strShowName = "DisplayName";

    Gen_Interface gen_if;
    int languageValue;
private:

    //  每次切换控制屏幕时,清空历史
    void clearHistory();

    //  用于把当前选中的目录或第三层界面封装成 PageState
    PageState getCurrentPageState();

    // 加载指定 PageState,相当于“跳转”到该状态
    void loadPageState(const PageState &st, bool isByHistoryNav = false);


    /**
     * @brief 从数据库加载指定 configId 下的目录记录,并构建树状结构
     * @param configId       配置ID
     * @param userPrivilege  当前用户权限
     */

    //!!!读数据库,修改为我们自己的数据库,或者封装对象
    void loadDirectories(int configId, const int &userPrivilege);

    /**
     * @brief 在给定父节点内,DFS 查找第一个第三层目录项
     * @param parentItem 父节点
     * @return 若找到第三层节点则返回指针,否则返回 nullptr
     */
    QStandardItem* findFirstThirdLevelItemDFS(QStandardItem *parentItem);

    /**
     * @brief 递归更新父级目录的复选框状态
     * @param item 当前变更的子项
     */
    void updateParentItems(QStandardItem *parentItem);

    /**
     * @brief 由 loadDirectories 获取的目录列表,构建树模型
     * @param directories 包含目录信息的 QJsonObject 列表
     */
    void buildTreeFromDirectories(const QList<QJsonObject> &directories);

    /**
     * @brief 更新父项的复选框状态(如果所有子项选中则父项也选中,否则取消)
     * @param item 当前变更的子项
     */
    void updateParentCheckState(QStandardItem *item);

    /**
     * @brief 更新按钮可见性:Home 界面隐藏,其他配置显示
     */
    void updateButtonsVisibility();

    /**
     * @brief 清理并隐藏第三层菜单内容
     */
    void clearThirdLevelMenu();

    /**
     * @brief 由给定的 DirectoryId 查询数据库中的字段信息(BondHead、Buttons)并返回
     * @param directoryId    目录ID
     * @param userPrivilege  当前用户权限
     * @return 包含第三层目录字段和按钮信息的 QJsonObject
     */

    //查询用户权限 !!!每次查询读取数据库,需要做修改
    //QJsonObject fetchThirdLevelData(int directoryId, const int &userPrivilege);

    /**
     * @brief 自定义事件过滤器,用于在 QTreeView 上绘制虚线等
     * @param watched 监视的对象
     * @param event   事件
     * @return 是否拦截事件
     */
    bool eventFilter(QObject *watched, QEvent *event) override;

    /**
     * @brief 递归绘制所有分支
     * @param parentIndex 父节点索引
     * @param painter     QPainter 引用
     */
    void paintAllBranches(const QModelIndex &parentIndex, QPainter &painter);

    /**
     * @brief 绘制父节点到子节点的“拐角线”
     * @param childIndex  子节点索引
     * @param painter     QPainter 引用
     */
    void drawParentChildLine(const QModelIndex &childIndex, QPainter &painter);

    /**
     * @brief 兄弟节点之间的竖线连接
     * @param childIndex  当前节点索引
     * @param painter     QPainter 引用
     */
    void drawSiblingLine(const QModelIndex &childIndex, QPainter &painter);

    /**
     * @brief 应用自定义样式(例如树的图标、复选框等)
     */
    void applyCustomStyles();

    /**
     * @brief 创建顶部按钮,并绑定槽函数
     */
    void setupButton();

    /**
     * @brief 创建并返回一个统一样式的分隔线 QFrame
     * @param parent 父对象
     * @param height 分隔线高度
     * @return 分隔线 QFrame 指针
     */
    QFrame* createUnifiedSeparator(QWidget *parent, int height);

    /**
     * @brief 更新分隔线位置和可见性(主要针对一级目录和其子项)
     */
    void updateSeparatorLine();

    /**
     * @brief 查找父节点下最后一个可见子项,用于放置分隔线
     * @param parentIndex 父节点索引
     * @return 最后一个可见子节点的索引
     */
    QModelIndex findLastVisibleChild(const QModelIndex &parentIndex);

    /**
     * @brief 更新导航栏,显示选中的路径信息
     * @param index 选中节点的 QModelIndex
     */
    void updateNavigationBar(const QModelIndex &index);

    /**
     * @brief 加载第三层目录按钮配置并在 widget_left 显示
     * @param thirdLevelObj 包含第三层目录 button 信息的 JSON
     */
    // 加载右侧按钮
   // void loadButtonConfigForThirdLevel(const QJsonObject &thirdLevelObj);

    void displayThirdLevelButtons(const QList<CONFIG_BASE_STRUCT>& buttons);

    /**
     * @brief 选中三级目录时显示控件,包括控件类型
     * @param Table_Control_Data    data
     * @param allChangeFalg 
     * @param  是否是 Home 界面,若是则填满 widget2
     */
    void displayThirdLevelFields(const QList<ST_TABLE_CONTROL_DATA>& data, bool allChangeFalg, bool isHome);


    /**
     * @brief 保存当前选中的复选框路径到 QSettings
     */
    void saveCheckedPaths();

    /**
     * @brief 从 QSettings 中加载复选框选中路径,并恢复
     */
    void loadCheckedPaths();

    /**
     * @brief 收集所有被选中的复选框路径
     * @return 被选中的路径列表,每项为 "Root/Child/Child"
     */
    QStringList collectCheckedPaths();

    /**
     * @brief 递归收集选中的路径
     * @param item 当前节点
     * @param path 当前路径
     * @return 收集到的选中路径列表
     */
    QStringList collectCheckedPathsRecursive(QStandardItem *item, QStringList path);

    /**
     * @brief 批量设置选中的复选框
     * @param checkedPathsList 已选中的路径列表
     */
    void setCheckedPaths(const QStringList &checkedPathsList);

    /**
     * @brief 构建节点的完整路径
     * @param item 当前 QStandardItem
     * @return 路径列表,如 ["Root", "Child", "Child2"]
     */
    QStringList buildItemPath(QStandardItem *item);

    /**
     * @brief 根据路径查找对应的节点索引
     * @param path 路径列表
     * @return 对应的 QModelIndex,若未找到则无效
     */
    QModelIndex findItemByPath(const QStringList &path);

    /**
     * @brief 检查权限,用于判断某字段/按钮是否可见
     * @param UserGrade      数据库中存储的权限列表,如 "1,2,3"
     * @param userPrivilege  当前用户权限
     * @return 是否包含此权限
     */
    bool hasPrivilege(const int &UserGrade, const int &userPrivilege);
    /**
     * @brief 实时的数据写入库
     * @param TableName      数据所在表的name
     * @param Id            在表中的id
     * @param currentValue  当前修改的id
     */
    //void updateDb(const QString &TableName, const int &Id,const QString currentValue);

    //封装一个函数,用于读取给定一级目录下的所有目录
   

};

#endif // DBTREEVIEWMANAGER_H