/**
 * 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 ROUTER_SERVER_H
#define ROUTER_SERVER_H

#include <map>
#include <vector>
#include <thread>
#include <condition_variable>
#include <atomic>

#include "bind_relation.h"
#include "queue_schedule/qs_client.h"
#include "common/bqs_status.h"
#include "common/bqs_msg.h"
#include "driver/ascend_hal.h"
#include "driver/ascend_hal_define.h"
#include "hccl/hccl_types_in.h"
#include "hccl/hccl_ex.h"
#include "config/config_info_operator.h"

namespace bqs {

enum class ThreadStatus : uint32_t {
    NOT_INIT,
    INIT_SUCCESS,
    INIT_FAIL,
};

class RouterServer {
public:
    static RouterServer& GetInstance();

    /**
     * Init bqs server, including init easycomm server
     * @return BQS_STATUS_OK:success other:failed
     */
    BqsStatus InitRouterServer(const InitQsParams& params);

    /**
     * Bqs server handle BqsMsg, get/getall deal now, bind/unbind send to work thread to deal
     * @return NA
     */
    void HandleBqsMsg(event_info& info);

    /**
     * Bqs server enqueue bind msg request process
     * @return NA
     */
    void BindMsgProc(const uint32_t index = 0U);

    /**
     * Bqs server destroy
     * @return NA
     */
    void Destroy();

    /**
     * get pipeline queueid
     * @return queue id
     */
    uint32_t GetPipelineQueueId() const;

    /**
     * get call hccl api flag
     * @return true
     * @return false
     */
    bool GetCallHcclFlag() const;

    void NotifyInitSuccess();

private:
    RouterServer();

    ~RouterServer();

    RouterServer(const RouterServer&) = delete;

    RouterServer(RouterServer&&) = delete;

    RouterServer& operator=(const RouterServer&) = delete;

    RouterServer& operator=(RouterServer&&) = delete;
    /**
     * Bqs server wait work thread to process msg
     * @return NA
     */
    BqsStatus WaitBindMsgProc();

    /**
     * Bqs server bind message processing function
     * @return BQS_STATUS_OK: success, other: failed.
     */
    BqsStatus ParseBindUnbindMsg() const;

    /**
     * Get relation detail information from mbuff, including (qsRouterHeadPtr_ aicpuRspHead_ subEventId_
     *                                                       qsRouterQueryPtr_ qsRouteListPtr_)
     * @return BQS_STATUS_OK: success, other: failed.
     */
    BqsStatus ParseRelationInfo(Mbuf** mbufPtr);
    /**
     * Bqs server bind query info from message
     * @return NA
     */
    void ParseGetBindNumMsg(const event_info& info);
    /**
     * Bqs server get bind message from mbuff
     * @return NA
     */
    BqsStatus ParseGetBindDetailMsg();
    /**
     * Bqs server get bind message by single queueid processing function
     * @return Number of query results
     */
    void GetBindRspBySingle(const EntityInfo& entityInfo, const uint32_t& queryType);

    /**
     * Bqs server get bind message by double queueid processing function
     * @return NA
     */
    void GetBindRspByDouble(const EntityInfo& src, const EntityInfo& dst, const uint32_t& queryType);

    void GetAllAbnormalBind();

    /**
     * Bqs server prcess get bind message and put data in buff
     * @return BQS_STATUS_OK: success, other: failed.
     */
    BqsStatus ProcessGetBindMsg(const uint32_t& queryType, const EntityInfo& src, const EntityInfo& dst);

    /**
     * Lisening bind/unbind/query message from aicpu-sd or acl
     * @return NA
     */
    void ManageQsEvent();

    /**
     * process bind initial
     * @return BQS_STATUS_OK: success, other: failed.
     */
    BqsStatus ProcessBindInit(const event_info& info);

    /**
     * process bind queue event
     * @return NA
     */
    void ProcessBindQueue(const uint32_t index);

    /**
     * process unbind queue event
     * @return NA
     */
    void ProcessUnbindQueue(const uint32_t index);

    /**
     * Send response event to acl or aicpu-sd
     * @return NA
     */
    void SendRspEvent(const int32_t result);

    /**
     * process event info
     * @return NA
     */
    void PreProcessEvent(const event_info& info);

    /**
     * process bind/unbind/query event
     * @return NA
     */
    void ProcessQueueRelationEvent(Mbuf* mbuf);

    /**
     * create queue for communicate between process
     * @return BQS_STATUS_OK: success, other: failed.
     */
    BqsStatus CreateAndGrantPipelineQueue();

    /**
     * attach and initial group at first
     * @return BQS_STATUS_OK: success, other: failed.
     */
    BqsStatus AttachAndInitGroup();

    /**
     * Construct a response message.
     * @return NA
     */
    void FillRspContent(QsProcMsgRsp& retRsp, const int32_t resultCode);

    /**
     * subscribe buf event
     * @return BQS_STATUS_OK: success, other: failed.
     */
    BqsStatus SubscribeBufEvent() const;

    /**
     * wait sync msg process
     * @return BQS_STATUS_OK:success, other:failed.
     */
    BqsStatus WaitSyncMsgProc();

    void FillRoutes(const EntityInfo& src, const EntityInfo& dst, const BindRelationStatus status);

    void ProcessConfigEvent(const QsOperType operType);

    void ProcessQueryLinkStatusEvent();

    bool AttachGroup();

    ThreadStatus PrePareForManageThread();

    EntityInfo CreateBasicEntityInfo(const uint32_t id, const dgw::EntityType eType) const;

    void SearchRelation(
        const MapEnitityInfoToInfoSet& relationMap, const EntityInfo& entityInfo, const BindRelationStatus status,
        bool bySrc);

    bool FindRelation(
        const MapEnitityInfoToInfoSet& relationMap, const EntityInfo& srcInfo, const EntityInfo& dstInfo) const;

    void TransRouteWithEntityInfo(
        const EntityInfo& srcInfo, const EntityInfo& dstInfo, const int32_t status, QueueRoute& routeInfo) const;

private:
    std::condition_variable cv_; // condition var to wait work thread process
    std::mutex mutex_;
    bool processing_;            // work thread is processing the bind request
    bool done_;                  // work thread has finished the bind request
    bool processingExtra_;
    bool doneExtra_;

    std::thread monitorQsEvent_;                  // listening bind/unbind/query event from aicpusd or app process
    uint32_t bindQueueGroupId_;                   // for recieving and sending bind/unbind/query event
    bool running_;                                // running flag
    uint32_t deviceId_;                           // device ID

    int32_t srcPid_;                              // Pid of source process for event commucation
    uint16_t srcVersion_;
    std::atomic<int32_t> srcGroupId_;             // groupId of of source process for event commucation
    std::atomic<uint32_t> pipelineQueueId_;       // queue for bind unbind query message data
    uint32_t subEventId_;                         // type of event
    std::vector<QueueRoute> queueRouteQueryList_; // bind relation and status list for query event
    QueueSchedulerRunMode deployMode_;            // 0:single process 1:allow multiple process 2:thread mode
    int32_t retCode_;                             // bind unbind result
    bool attachedFlag_;                           // current process need to attach group or not
    bool isAicpuEvent_;                           // event from aicpu
    QueueRoute* qsRouteListPtr_;                  // bind unbind query msg pointer
    QsRouteHead* qsRouterHeadPtr_;                // bind unbind query msg header pointer
    QueueRouteQuery* qsRouterQueryPtr_;           // query msg pointer
    event_sync_msg* drvSyncMsg_;                  // event head from acl request by calling sync event interface
    uint64_t aicpuRspHead_;                       // event head from aicpu
    std::string qsInitGroupName_;                 // group name send from parameters
    uint32_t f2nfGroupId_;
    uint64_t schedPolicy_;
    // config info operator
    std::unique_ptr<ConfigInfoOperator> cfgInfoOperator_;
    // call hccl api flag
    bool callHcclFlag_;
    bool numaFlag_;
    bool readyToHandleMsg_;
    std::mutex manageThreadMutex_;
    std::condition_variable manageThreadCv_; // condition var to wait manage thread to ready
    ThreadStatus manageThreadStatus_;        // 0:uninit, 1:success, 2:failed
    bool needAttachGroup_;
    bool compatMsg_;
};
} // namespace bqs
#endif // ROUTER_SERVER_H