/**

 * Copyright (c) 2025 Huawei Technologies Co., Ltd.

 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of

 * CANN Open Software License Agreement Version 2.0 (the "License").

 * Please refer to the License for details. You may not use this file except in compliance with the License.

 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,

 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.

 * See LICENSE in the root of the software repository for the full text of the License.

 */



#ifndef DGW_CLIENT_H

#define DGW_CLIENT_H



#include <memory>

#include <string>

#include <vector>

#include <utility>

#include <list>

#include "common/type_def.h"

#include "queue_schedule/qs_client.h"



namespace bqs {

// max ip len

constexpr size_t MAX_IP_LEN = 16UL;

// max tag name len

constexpr size_t MAX_TAG_NAME_LEN = 128UL;



// config command for datagw

enum class ConfigCmd : int32_t {

    DGW_CFG_CMD_BIND_ROUTE = 0,

    DGW_CFG_CMD_UNBIND_ROUTE = 1,

    DGW_CFG_CMD_QRY_ROUTE = 2,

    DGW_CFG_CMD_ADD_GROUP = 3,

    DGW_CFG_CMD_DEL_GROUP = 4,

    DGW_CFG_CMD_QRY_GROUP = 5,

    DGW_CFG_CMD_RESERVED = 6,

    DGW_CFG_CMD_UPDATE_PROFILING = 7,

    DGW_CFG_CMD_SET_HCCL_PROTOCOL = 8,

    DGW_CFG_CMD_INIT_DYNAMIC_SCHEDULE = 9,

    DGW_CFG_CMD_STOP_SCHEDULE = 10,

    DGW_CFG_CMD_CLEAR_AND_RESTART_SCHEDULE = 11

};



// endpoint type

enum class EndpointType : int32_t {

    QUEUE = 0,

    MEM_QUEUE = 1,

    GROUP = 2,

    COMM_CHANNEL = 3,

};



// endpoint status

enum class EndpointStatus : int32_t {

    AVAILABLE = 0,

    UNAVAILABLE = 1,

};



// route status

enum class RouteStatus : int32_t {

    ACTIVE = 0,

    INACTIVE = 1,

    ERROR = 2,

};



// group policy

enum class GroupPolicy : int32_t {

    HASH = 0,

    BROADCAST = 1,

    DYNAMIC = 2,

};



// Query mode

enum class QueryMode : int32_t {

    DGW_QUERY_MODE_SRC_ROUTE = 0,

    DGW_QUERY_MODE_DST_ROUTE = 1,

    DGW_QUERY_MODE_SRC_DST_ROUTE = 2,

    DGW_QUERY_MODE_ALL_ROUTE = 3,

    DGW_QUERY_MODE_GROUP = 4,

    DGW_QUERY_MODE_RESERVED = 5,

};



// qs scheduling policy

enum class SchedPolicy : uint64_t {

    POLICY_UNSUB_F2NF = 1UL,

    POLICY_SUB_BUF_EVENT = 2UL,

};



enum class ProfilingMode : uint32_t {

    PROFILING_CLOSE = 0U,

    PROFILING_OPEN = 1U,

};



enum class HcclProtocolType : uint32_t {

    RDMA = 0U,

    TCP = 1U,

};



#pragma pack(push, 1)

// queue attr: can not named QueueAttr, duplicatable name with driver

struct FlowQueueAttr {

    int32_t queueId; // queue id

};



struct MemQueueAttr {

    int32_t queueId;    // queue id

    uint32_t queueType; // localQ:0 or clientQ:1

    uint32_t rsv[7];

};



// communication channel attr

struct CommChannelAttr {

    uint64_t handle;        // hcom handle

    uint32_t localTagId;    // local tag id

    uint32_t peerTagId;     // peer tag id

    uint32_t localRankId;   // local rank id

    uint32_t peerRankId;    // peer rank id

    uint32_t localTagDepth; // local tag depth

    uint32_t peerTagDepth;  // peer tag depth

    uint32_t memType;       // memType: 1-dvpp

    uint32_t rsv[7];        // reserved field

};



// group attr

struct GroupAttr {

    int32_t groupId;      // group id

    GroupPolicy policy;   // only need set for dstination group

    uint32_t endpointNum; // only used for query result

    uint32_t rootModelId;

};



// endpoint: queue, communication channel, group

struct Endpoint {

    EndpointType type;               // endpoint type

    EndpointStatus status;           // endpoint status

    uint32_t peerNum;                // total instances, used by srcGroup

    uint32_t localId;                // self id, started by 0, used by srcGroup

    uint32_t globalId;               // endpoint global id

    uint32_t modelId;

    uint16_t resId;                  // resId

    uint32_t rootModelId;

    char_t rsv[10];                  // reserved field

    union {

        FlowQueueAttr queueAttr;     // queue attr

        MemQueueAttr memQueueAttr;   // mem queue attr

        CommChannelAttr channelAttr; // communication channel attr

        GroupAttr groupAttr;         // group attr

    } attr;

};



// group query

struct GroupQuery {

    uint32_t endpointNum; // endpoint num, return value

    int32_t groupId;      // group id

};



// route query

struct RouteQuery {

    uint32_t routeNum; // route num, return value

    Endpoint src;      // src endpoint

    Endpoint dst;      // dst endpoint

};



// route query or group query

struct ConfigQuery {

    QueryMode mode;          // query mode

    union {

        GroupQuery groupQry; // group query

        RouteQuery routeQry; // route query

    } qry;

};



// group config

struct GroupConfig {

    int32_t groupId;      // group id, created by datagw server

    uint32_t endpointNum; // endpoint number

    Endpoint* endpoints;  // multi queue or channel, memory malloc by user

};



// route info

struct Route {

    RouteStatus status; // route status

    Endpoint src;       // src endpoint

    Endpoint dst;       // dst endpoint

    char_t rsv[32];     // reserved param

};



// routes config

struct RoutesConfig {

    uint32_t routeNum; // route number

    Route* routes;     // routes, memory malloc by user

};



// profiling config

struct ProfilingConfig {

    ProfilingMode profMode; // profiling mode

};



struct HcclProtocolConfig {

    HcclProtocolType protocol;

};



struct DynamicSchedQueueAttr {

    uint32_t queueId;

    uint32_t deviceId;

    int32_t deviceType;

    uint32_t globalLogicId;

    bool isClientQ;

};



struct DynamicSchedConfigV2 {

    uint32_t rootModelId;

    DynamicSchedQueueAttr requestQ;

    DynamicSchedQueueAttr responseQ;

    char rsv[26];

};



struct ReDeployConfig {

    uint64_t rootModelIdsAddr; // ptr which point to rootModelIds(uint32_t)

    uint32_t rootModelNum;     // rootModelId's number

    char rsv[4];

};



// config info, group config or routes config

struct ConfigInfo {

    ConfigCmd cmd;               // query mode, user don’t need fill this param

    union {

        GroupConfig groupCfg;    // group config

        RoutesConfig routesCfg;  // routes config

        ProfilingConfig profCfg; // profiling config

        HcclProtocolConfig hcclProtocolCfg;

        DynamicSchedConfigV2* dynamicSchedCfgV2;

        ReDeployConfig reDeployCfg;

    } cfg;

};



// identify info in mbuf head

struct IdentifyInfo {

    uint64_t transId = 0UL; // transaction id

    char_t rsv[52];         // reserved param

    uint32_t routeLabel;

};



#pragma pack(pop)



class __attribute__((visibility("default"))) DgwClient {

public:

    /**

     * Create instance of dgwClient.

     * @param deviceId  The id of self cpu.

     * @return std::shared_ptr<DgwClient>: DgwClient ptr

     */

    static std::shared_ptr<DgwClient> GetInstance(const uint32_t deviceId);



    static std::shared_ptr<DgwClient> GetInstance(const uint32_t deviceId, const pid_t qsPid);



    static std::shared_ptr<DgwClient> GetInstance(const uint32_t deviceId, const pid_t qsPid, const bool proxy);



    /**

     * Initialize dgw server

     * @param dgwPid dgw server process id

     * @param procSign procSign

     * @return 0:success, other:failed.

     */

    int32_t Initialize(

        const uint32_t dgwPid, const std::string procSign, const bool isProxy = false, const int32_t timeout = -1);



    /**

     * Destroy dgw client

     * @param dgwPid dgw server process id

     * @param procSign procSign

     * @return 0:success, other:failed.

     */

    int32_t Finalize();



    /**

     * Create hccl communication handle

     * @param rankTable rank table

     * @param rankId rank id

     * @param reserve reserve params

     * @param handle handle

     * @return  0:success, other:failed.

     */

    int32_t CreateHcomHandle(

        const std::string& rankTable, const int32_t rankId, const void* const reserve, uint64_t& handle,

        const int32_t timeout = -1);



    /**

     * Destroy hccl communication handle

     * @param handle handle

     * @return 0:success, other:failed.

     */

    int32_t DestroyHcomHandle(const uint64_t handle, const int32_t timeout = -1);



    /**

     * Construct a new DgwClient object

     * @param deviceId device Id

     */

    explicit DgwClient(const uint32_t deviceId);



    explicit DgwClient(const uint32_t deviceId, const pid_t qsPid);



    explicit DgwClient(const uint32_t deviceId, const pid_t qsPid, const bool proxy);



    /**

     * Destroy the DgwClient object - default method

     */

    ~DgwClient() = default;



public:

    /**

     * Update route config or group config

     * config routes: any route config failed, return failed

     * config group: group config failed, return failed

     * @param cfgInfo group config or route config

     * @param cfgRets config results

     * @return 0:success, other:failed.

     */

    int32_t UpdateConfig(ConfigInfo& cfgInfo, std::vector<int32_t>& cfgRets, const int32_t timeout = -1);



    /**

     * Query Route number or endpoint number in group

     * @param query config query info

     * @return 0:success, other:failed.

     */

    int32_t QueryConfigNum(ConfigQuery& query, const int32_t timeout = -1);



    /**

     * Query routes or group config

     * @param query config query info

     * @param cfgInfo routes config or group config

     * @return 0:success, other:failed.

     */

    int32_t QueryConfig(const ConfigQuery& query, ConfigInfo& cfgInfo, const int32_t timeout = -1);



    /**

     * wait config effect

     * @param timeout(s)

     * @return 0:success, other:failed.

     */

    int32_t WaitConfigEffect(const uint64_t timeout);



    /**

     * wait config effect

     * @param rsv 0:等待tag建链完成,如果没有tag要建链也直接返回成功

     * @param timeout(s)

     * @return 0:success, other:failed.

     */

    int32_t WaitConfigEffect(const int32_t rsv, const int32_t timeout);



private:

    // config params for reducing parameters of API, only used inner

    struct ConfigParams {

        HcomHandleInfo* info; // hcom handle info, only invalid for create hcom handle

        ConfigQuery* query;   // config query, only invalid for query

        ConfigInfo* cfgInfo;  // config info

        size_t cfgLen;        // config length

        size_t totalLen;      // total length for mbuf

    };



private:

    /**

     * Send synchronization event

     * @param msg message

     * @param msgLen message length

     * @param subEventId subevent id

     * @param timeout  ms

     * @param qsProcMsgRsp return value

     * @return 0:success, other:failed.

     */

    int32_t SendEventToQsSync(

        const void* const msg, const size_t msgLen, const QueueSubEventType subEventId, QsProcMsgRsp& qsProcMsgRsp,

        const int32_t timeout = -1) const;

    /**

     * Check and calculate config info length

     * @param cfgInfo config info

     * @param cfgLen config length

     * @param dataList data list which need copy to mbuf

     * @param spareRoutes spare routes which transform memq to q

     * @param spareEndpoints spare endpoint which transform memq to q

     * @return 0:success, other:failed.

     */

    int32_t CalcConfigInfoLen(

        const ConfigInfo& cfgInfo, size_t& cfgLen, std::list<std::pair<uintptr_t, size_t>>& dataList,

        std::unique_ptr<Route[]>& spareRoutes, std::unique_ptr<Endpoint[]>& spareEndpoints) const;



    /**

     * Get operate configuration result

     * @param cfgInfo config info

     * @param mbufData mbuf data addr

     * @param cfgLen config info len

     * @param cfgRets config results only for update config

     * @param cmdRet command result

     * @return 0:success, other:failed.

     */

    int32_t GetOperateConfigRet(

        ConfigInfo& cfgInfo, const uintptr_t mbufData, const size_t cfgLen, std::vector<int32_t>& cfgRets,

        int32_t& cmdRet) const;



    /**

     * Get operate configuration result

     * @param subEventId subevent id

     * @param cfgParams config params

     * @param dataList data list which need copy to mbuf

     * @param cfgRets config results only for update config

     * @return 0:success, other:failed.

     */

    int32_t OperateConfigToServer(

        const QueueSubEventType subEventId, const ConfigParams& cfgParams,

        std::list<std::pair<uintptr_t, size_t>>& dataList, std::vector<int32_t>& cfgRets, const int32_t timeout = -1);



    /**

     * Calculate result length

     * @param cfgInfo config info

     * @param retLen result length

     * @return 0:success, other:failed.

     */

    int32_t CalcResultLen(const ConfigInfo& cfgInfo, size_t& retLen) const;



    /**

     * Get query config num result

     * @param query config query

     * @param mbufData mbuf data

     * @param cmdRet cmd result

     * @return 0:success, other:failed.

     */

    int32_t GetQryConfigNumRet(ConfigQuery& query, const uintptr_t mbufData, int32_t& cmdRet) const;



    /**

     * Query and check config num

     * @param query config query

     * @param cfgInfo config info

     * @return 0:success, other:failed.

     */

    int32_t CheckConfigNum(const ConfigQuery& query, ConfigInfo& cfgInfo);



    /**

     * Get operate group result

     * @param cfgInfo config info

     * @param mbufData mbuf data addr

     * @param cfgLen config info len

     * @param cfgRets config results only for update config

     * @param cmdRet command result

     * @return 0:success, other:failed.

     */

    int32_t GetUpdateGroupRet(

        ConfigInfo& cfgInfo, const uintptr_t mbufData, const size_t cfgLen, std::vector<int32_t>& cfgRets,

        int32_t& cmdRet) const;



    /**

     * Get operate route result

     * @param cfgInfo config info

     * @param mbufData mbuf data addr

     * @param cfgLen config info len

     * @param cfgRets config results only for update config

     * @param cmdRet command result

     * @return 0:success, other:failed.

     */

    int32_t GetUpdateRouteRet(

        const ConfigInfo& cfgInfo, const uintptr_t mbufData, const size_t cfgLen, std::vector<int32_t>& cfgRets,

        int32_t& cmdRet) const;



    /**

     * Get query route result

     * @param cfgInfo config info

     * @param mbufData mbuf data addr

     * @param cfgLen config info len

     * @param cfgRets config results only for update config

     * @param cmdRet command result

     * @return 0:success, other:failed.

     */

    int32_t GetQryRouteRet(

        const ConfigInfo& cfgInfo, const uintptr_t mbufData, const size_t cfgLen, std::vector<int32_t>& cfgRets,

        int32_t& cmdRet) const;



    /**

     * Get query group result

     * @param cfgInfo config info

     * @param mbufData mbuf data addr

     * @param cfgLen config info len

     * @param cfgRets config results only for update config

     * @param cmdRet command result

     * @return 0:success, other:failed.

     */

    int32_t GetQryGroupRet(

        const ConfigInfo& cfgInfo, const uintptr_t mbufData, const size_t cfgLen, std::vector<int32_t>& cfgRets,

        int32_t& cmdRet) const;



    /**

     * Get operate hcom handle result

     * @param subEventId sub event id

     * @param info hcom handle info

     * @param mbufData mbuf data

     * @param cfgLen config info len

     * @param cmdRet command result

     * @return 0:success, other:failed.

     */

    int32_t GetOperateHcomHandleRet(

        const QueueSubEventType subEventId, HcomHandleInfo& info, const uintptr_t mbufData, const size_t cfgLen,

        int32_t& cmdRet) const;



    int32_t ProcessEndpointDeviceId(Endpoint& endpoint) const;



private:

    int32_t OperateToServerOnSameSide(

        const QueueSubEventType subEventId, const ConfigParams& cfgParams,

        std::list<std::pair<uintptr_t, size_t>>& dataList, std::vector<int32_t>& cfgRets, const int32_t timeout);

    int32_t OperateToServerOnOtherSide(

        const QueueSubEventType subEventId, const ConfigParams& cfgParams,

        std::list<std::pair<uintptr_t, size_t>>& dataList, std::vector<int32_t>& cfgRets, const int32_t timeout);

    void ExtractRetCode(

        const QueueSubEventType subEventId, const ConfigParams& cfgParams, const uintptr_t respPtr,

        std::vector<int32_t>& cfgRets, int32_t& cmdRet) const;

    int32_t InformServer(const QueueSubEventType subEventId, int32_t& cmdRet, const int32_t timeout);



    static int32_t GetPlatformInfo(const uint32_t deviceId);



    static bool IsNumeric(const std::string& str);



    static bool IsSupportSetVisibleDevices();



    static void SplitString(const std::string& str, std::vector<std::string>& result);



    static bool GetVisibleDevices();



    static int32_t ChangeUserDeviceIdToLogicDeviceId(const uint32_t userDevId, uint32_t& logicDevId);



    static int32_t ChangeDynamicScheduleDeviceId(const ConfigInfo& cfgInfo);



    uint32_t deviceId_;

    // dgw server pid

    pid_t qsPid_;

    // proc sign

    std::string procSign_;

    // dgw client pid

    pid_t curPid_;

    // dgw client group id

    uint32_t curGroupId_;

    // dgw client and qs server pipline queue id

    uint32_t piplineQueueId_;

    // dgw initialized flag

    bool initFlag_;

    std::mutex eventMutex_;

    std::mutex mutexForWaitConfig;

    bool isProxy_;

    bool isServerOldVersion_;

};

} // namespace bqs

#endif