#ifndef M4255NFCHELPER_H
#define M4255NFCHELPER_H

#include "RS485Controller.h"
#include <QObject>
#include <QScopedPointer>
#include <QMutex>
#include <QReadWriteLock>

// 错误码定义
namespace NFCError {
    constexpr int SUCCESS = 0;           // 成功
    constexpr int NOT_INITIALIZED = -1;  // 未初始化
    constexpr int TIMEOUT = -2;          // 超时
    constexpr int INVALID_CARD = -3;     // 无效卡
    constexpr int INVALID_PARAM = -4;    // 无效参数
    constexpr int DEVICE_ERROR = -5;     // 设备错误
    constexpr int COMMUNICATION_ERROR = -6; // 通信错误
}

/**
 * @brief M4255NFCHelper 类用于控制和管理 M4255 NFC 设备。
 *
 * 该类提供了与 M4255 NFC 设备进行通信和操作的一系列接口，包括设备初始化、端口控制、卡操作、预付费卡操作以及设备配置等。
 * 通过该类，用户可以方便地与 NFC 设备进行交互，执行如读取卡 ID、读写数据块、设置设备工作模式等操作。
 *
 * 使用示例：
 *
 * 构造函数参数：
 * - QObject *parent：指定父对象，默认为 nullptr。
 *
 * 特殊使用限制或潜在的副作用：
 * - 该类是单例模式，只能通过 instance() 方法获取实例。
 * - 禁止拷贝和赋值操作。
 * - 在使用任何设备操作接口前，必须先调用 init() 方法进行设备初始化。
 * - 设备配置接口中的某些操作可能会影响设备的当前状态，使用时需谨慎。
 */
class M4255NFCHelper : public QObject
{
    Q_OBJECT

public:
    /**
     * @brief 获取M4255NFCHelper的单例实例。
     * @return 返回M4255NFCHelper的单例指针。
     */
    // static M4255NFCHelper* instance();

    /**
     * @brief 构造函数，初始化M4255NFCHelper对象。
     * @param parent QObject父对象指针，默认为nullptr。
     */
    explicit M4255NFCHelper(QObject *parent = nullptr);

    /**
     * @brief 析构函数，释放M4255NFCHelper对象。
     */
    ~M4255NFCHelper();

    /**
     * @brief 禁止拷贝构造函数。
     */
    M4255NFCHelper(const M4255NFCHelper&) = delete;

    /**
     * @brief 禁止赋值操作符。
     */
    M4255NFCHelper& operator=(const M4255NFCHelper&) = delete;

public:
    /**
     * @brief 关闭端口。
     */
    void closePort();

    /**
     * @brief 初始化设备。
     * @param portName 端口名称。
     * @return 返回初始化结果，0表示成功，其他值表示错误码。
     */
    int init(const QString& portName);

    /**
     * @brief 检查设备是否已初始化。
     * @return 返回设备初始化状态，true表示已初始化，false表示未初始化。
     */
    bool isInitialized() const { return m_isInitialized; }

    /**
     * @brief 检查端口是否已打开。
     * @return 返回端口打开状态，true表示已打开，false表示未打开。
     */
    bool isPortOpen();

    /**
     * @brief 读取卡ID。
     * @param cardType 卡类型。
     * @param cardID 卡ID。
     * @return 返回读取结果，0表示成功，其他值表示错误码。
     */
    int readCardId(QByteArray& cardType, QByteArray& cardID);

    /**
     * @brief 读取数据块。
     * @param useKeyB 是否使用KeyB。
     * @param blockId 数据块ID。
     * @param buff 数据缓冲区。
     * @return 返回读取结果，0表示成功，其他值表示错误码。
     */
    int readDataBlock(const uint8_t& useKeyB, const uint8_t blockId, QByteArray& buff);

    /**
     * @brief 填充数据块。
     * @param useKeyB 是否使用KeyB。
     * @param blockId 数据块ID。
     * @param data 要填充的数据。
     * @return 返回填充结果，0表示成功，其他值表示错误码。
     */
    int fillDataBlock(const uint8_t& useKeyB, const uint8_t blockId, const QByteArray& data);

    /**
     * @brief 填充PIN。
     * @param data 要填充的PIN数据。
     * @return 返回填充结果，0表示成功，其他值表示错误码。
     */
    int fillPIN(const QByteArray& data);

    /**
     * @brief 填充ORG。
     * @param data 要填充的ORG数据。
     * @return 返回填充结果，0表示成功，其他值表示错误码。
     */
    int fillORG(const QByteArray& data);

    /**
     * @brief 填充PIN块。
     * @param useKeyB 是否使用KeyB。
     * @param block_id 数据块ID。
     * @param keyA KeyA。
     * @param keyB KeyB。
     * @return 返回填充结果，0表示成功，其他值表示错误码。
     */
    int fillPINBlock(const uint8_t& useKeyB, const uint8_t& block_id, 
                     const QByteArray& keyA, const QByteArray& keyB);

    /**
     * @brief 初始化预付费IC卡。
     * @param useKeyB 是否使用KeyB。
     * @param blockId 数据块ID。
     * @param value 初始化值。
     * @return 返回初始化结果，0表示成功，其他值表示错误码。
     */
    int initPrepaidIC(const uint8_t& useKeyB, const uint8_t& blockId, const uint32_t& value);

    /**
     * @brief 预付费IC卡扣款。
     * @param useKeyB 是否使用KeyB。
     * @param blockId 数据块ID。
     * @param value 扣款金额。
     * @return 返回扣款结果，0表示成功，其他值表示错误码。
     */
    int subPrepaidIC(const uint8_t& useKeyB, const uint8_t& blockId, const uint32_t& value);

    /**
     * @brief 预付费IC卡充值。
     * @param useKeyB 是否使用KeyB。
     * @param blockId 数据块ID。
     * @param value 充值金额。
     * @return 返回充值结果，0表示成功，其他值表示错误码。
     */
    int addPrepaidIC(const uint8_t& useKeyB, const uint8_t& blockId, const uint32_t& value);

    /**
     * @brief 读取预付费IC卡余额。
     * @param useKeyB 是否使用KeyB。
     * @param blockId 数据块ID。
     * @param value 余额。
     * @return 返回读取结果，0表示成功，其他值表示错误码。
     */
    int readPrepaidIC(const uint8_t& useKeyB, const uint8_t& blockId, uint32_t& value);

    /**
     * @brief 设置蜂鸣器状态。
     * @param on 是否开启蜂鸣器。
     * @return 返回设置结果，0表示成功，其他值表示错误码。
     */
    int setBeep(const uint8_t& on);

    /**
     * @brief 强制设置蜂鸣器状态。
     * @param on 是否开启蜂鸣器。
     * @return 返回设置结果，0表示成功，其他值表示错误码。
     */
    int forceBeep(const uint8_t& on);

    /**
     * @brief 设置工作模式。
     * @param mode 工作模式。
     * @return 返回设置结果，0表示成功，其他值表示错误码。
     */
    int setWorkMode(const uint8_t& mode);

    /**
     * @brief 设置读取一次模式。
     * @param type 读取类型。
     * @return 返回设置结果，0表示成功，其他值表示错误码。
     */
    int setReadOnce(const uint8_t& type);

    /**
     * @brief 等待读取卡ID。
     * @param cardId 卡ID。
     * @param timeout 超时时间，默认为3000毫秒。
     * @return 返回读取结果，0表示成功，其他值表示错误码。
     */
    int waitReadCardId(QByteArray& cardId, int timeout = 3000);

private:
    /**
     * @brief 计算校验和。
     * @param data 数据。
     * @param len 数据长度。
     * @return 返回校验和。
     */
    uint8_t checkSum(const QByteArray& data, int len);

    /**
     * @brief 发送命令。
     * @param command 命令数据。
     * @param timeout 超时时间。
     * @return 返回发送结果，0表示成功，其他值表示错误码。
     */
    int sendCommand(const QByteArray& command, int timeout);

    /**
     * @brief 解析响应数据。
     * @param data 响应数据。
     * @param expectedLength 期望数据长度。
     * @param successCode 成功码。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseResponse(const QByteArray& data, int expectedLength, int successCode);
    
    /**
     * @brief 打开端口。
     * @param portName 端口名称，默认为"/dev/ttys2"。
     * @param baudRate 波特率，默认为9600。
     * @param dataBits 数据位，默认为8。
     * @param parity 奇偶校验，默认为无。
     * @param stopBits 停止位，默认为1。
     * @param flowControl 流控制，默认为无。
     * @return 返回打开结果，true表示成功，false表示失败。
     */
    bool openPort(const QString& portName = "/dev/ttys2",
                 qint32 baudRate = QSerialPort::Baud9600,
                 QSerialPort::DataBits dataBits = QSerialPort::Data8,
                 QSerialPort::Parity parity = QSerialPort::NoParity,
                 QSerialPort::StopBits stopBits = QSerialPort::OneStop,
                 QSerialPort::FlowControl flowControl = QSerialPort::NoFlowControl);

    /**
     * @brief 解析卡ID接收数据。
     * @param data 接收数据。
     * @param cardType 卡类型。
     * @param cardID 卡ID。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseCardIdRecvData(const QByteArray& data, QByteArray& cardType, QByteArray& cardID);

    /**
     * @brief 解析读取数据块接收数据。
     * @param data 接收数据。
     * @param buff 数据缓冲区。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseReadDataBlockRecvData(const QByteArray& data, QByteArray& buff);

    /**
     * @brief 解析填充数据块接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseFillDataBlockRecvData(const QByteArray& data);

    /**
     * @brief 解析填充PIN接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseFillPinRecvData(const QByteArray& data);

    /**
     * @brief 解析填充ORG接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseFillOrgRecvData(const QByteArray& data);

    /**
     * @brief 解析填充PIN块接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseFillPinBlockRecvData(const QByteArray& data);

    /**
     * @brief 解析初始化预付费IC卡接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseInitPrepaidICRecvData(const QByteArray& data);

    /**
     * @brief 解析预付费IC卡扣款接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseSubPrepaidICRecvData(const QByteArray& data);

    /**
     * @brief 解析预付费IC卡充值接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseAddPrepaidICRecvData(const QByteArray& data);

    /**
     * @brief 解析读取预付费IC卡余额接收数据。
     * @param data 接收数据。
     * @param value 余额。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseReadPrepaidICRecvData(const QByteArray& data, uint32_t &value);

    /**
     * @brief 解析设置蜂鸣器接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseSetBeepRecvData(const QByteArray& data);

    /**
     * @brief 解析强制设置蜂鸣器接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseForceBeepRecvData(const QByteArray& data);

    /**
     * @brief 解析设置工作模式接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseSetWorkModeRecvData(const QByteArray& data);

    /**
     * @brief 解析设置读取一次模式接收数据。
     * @param data 接收数据。
     * @return 返回解析结果，0表示成功，其他值表示错误码。
     */
    int parseSetReadOnceRecvData(const QByteArray& data);

    /**
     * @brief 通用接收数据处理。
     * @param data 接收数据。
     * @return 返回处理结果，0表示成功，其他值表示错误码。
     */
    int generalRecvData(const QByteArray& data);

private slots:
    /**
     * @brief 解析接收到的响应数据。
     * @param data 响应数据。
     */
    void parseResponseReceived(const QByteArray& data);

    /**
     * @brief 解析接收到的数据。
     * @param data 接收数据。
     */
    void parseReceiveData(const QByteArray& data);

    /**
     * @brief 解析发生的错误。
     * @param errorString 错误信息。
     */
    void parseErrorOccurred(const QString& errorString);

signals:
    /**
     * @brief 等待读取卡ID信号。
     */
    void signalWaitReadCardId();

    /**
     * @brief 错误发生信号。
     * @param errorCode 错误码。
     * @param errorMessage 错误信息。
     */
    void errorOccurred(int errorCode, const QString& errorMessage);

private:
    RS485Controller * m_controller;                     /**< RS485控制器指针。 */
    QByteArray m_recvData;                              /**< 接收数据缓冲区。 */
    QReadWriteLock m_lock;                              /**< 读写锁。 */
    bool m_isInitialized;                               /**< 设备初始化状态。 */
    int m_retryCount;                                   /**< 重试计数。 */
    static QMutex s_mutex;                              /**< 静态互斥锁。 */
    bool m_isPortOpen = false;                          /**< 端口打开状态。 */
};

// 全局访问宏
// #define NFCReader M4255NFCHelper::instance()

#endif // M4255NFCHELPER_H
