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

#include <vector>
#include <thread>
#include <atomic>
#include <set>
#include <string>
#include <condition_variable>
#include "driver/ascend_hal.h"
#include "common/bqs_status.h"
#include "common/bqs_msg.h"
#include "bind_relation.h"
namespace bqs {
class QueueSchedule {
public:
    /**
     * QueueSchedule construct.
     * @param deviceId device chip id.
     * @param enqueGroupId enqueue group id.
     * @param f2nfGroupId full to not full group id.
     */
    explicit QueueSchedule(const InitQsParams& params)
        : deviceId_(params.deviceId),
          enqueGroupId_(params.enqueGroupId),
          f2nfGroupId_(params.f2nfGroupId),
          running_(false),
          hasAICPU_(true),
          isZeroSizeAicpuNum_(false),
          reschedInterval_(params.reschedInterval),
          runMode_(params.runMode),
          qsInitGroupName_(params.qsInitGrpName),
          initQsParams_(params),
          abnormalInterval_(0U)
    {}

    ~QueueSchedule();

    QueueSchedule(const QueueSchedule&) = delete;

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

    QueueSchedule(QueueSchedule&&) = delete;

    QueueSchedule& operator=(QueueSchedule&&) = delete;

public:
    /**
     * Init and start working.
     * @return BQS_STATUS_OK:success, other:failed
     */
    BqsStatus StartQueueSchedule();

    /* *
     * stop working.
     */
    void StopQueueSchedule();

    /**
     * destroy source.
     */
    void Destroy() const;

    /**
     * enqueue event working thread function
     * @param threadIndex: thread index
     * @param bindCpuIndex: bind cpu index
     * @param groupId: wait event group
     */
    void EnqueueThreadTask(
        const uint32_t deviceId, const uint32_t threadIndex, const uint32_t bindCpuIndex, const uint32_t groupId,
        const uint32_t index);

    /**
     * full to not full working thread function
     * @param threadIndex: thread index
     * @param bindCpuIndex: bind cpu index
     * @param groupId: wait event group
     */
    void F2NFThreadTask(const uint32_t threadIndex, const uint32_t bindCpuIndex, const uint32_t groupId);

    /**
     * daemon thread run function
     */
    void DaemonThreadTask(const uint32_t index);

    /**
     * wait for stop.
     */
    void WaitForStop();

    void ReportAbnormal() const;

private:
    /**
     * handle enqueue event.
     * @param threadIndex thread index
     * @param event event
     */
    void ProcessEnqueueEvent(
        const uint32_t threadIndex, const event_info& event, const uint32_t index = 0U, const bool procF2NF = false);

    /**
     * process enqueue event loop.
     * @param threadIndex thread index
     * @param groupId groupId
     */
    void LoopProcessEnqueueEvent(
        const uint32_t threadIndex, const uint32_t deviceId, const uint32_t groupId, const uint32_t index);

    /**
     * start enqueue thread.
     * @param threadNum thread total num
     * @param aicpuBeginIndex begin index
     */
    BqsStatus StartThreadGroup(
        const uint32_t threadNum, const uint32_t deviceId, const uint32_t enqueGroupId, const uint32_t index);

    /**
     * start enqueue thread.
     * @param threadIndex thread id
     * @param bindCpuIndex cpu index
     */
    void BindAicpu(const uint32_t threadIndex, const uint32_t bindCpuIndex);

    /**
     * handle enqueue event in daemon thread
     */
    void DaemonEnqueueEvent(const uint32_t index);

    /**
     * schedule data buff for all queue.
     * @param dataEnqueue true means data enqueue, false means relation or f2nf enqueue
     */
    void ScheduleDataBuffAll(const bool dataEnqueue, const uint32_t index = 0U) const;

    /**
     * process full entity
     * @param entity entity
     */
    dgw::FsmStatus ProcessDstEntity(const EntityInfo& entity, const uint32_t index) const;

    /**
     * init drv event scheduler.
     * @return BQS_STATUS_OK: success, other: error
     */
    BqsStatus InitDrvSchedModule(
        const uint32_t deviceId, const uint32_t enqueGroupId, const uint32_t f2nfGroupId) const;

    /**
     * process event
     * @param event esched event info
     */
    BqsStatus ProcessEvent(const uint32_t threadIndex, event_info& event, const uint32_t index);

    void CheckIfRecover(
        uint32_t& errCount, const char_t* const identity, const uint32_t threadIndex, const uint32_t groupId) const;

    void DynamicSchedule(const uint32_t index) const;

    void ProcessFullToNotFullEvent(const uint32_t index);

    BqsStatus InitExtraSchedule(const std::set<uint32_t>& resDevids, uint32_t threadNum);

    /**
     * device chip id.
     */
    uint32_t deviceId_;

    /**
     * enqueue event group id.
     */
    uint32_t enqueGroupId_;

    /**
     * full to not full event group id.
     */
    uint32_t f2nfGroupId_;

    /**
     * thread run flag.
     */
    volatile bool running_;

    /**
     * daemon thread sleep for a while.
     */
    std::condition_variable daemonWait_;

    /**
     * run on aicpu flag.
     */
    bool hasAICPU_;

    /**
     * run on aicpu flag.
     */
    bool isZeroSizeAicpuNum_;

    /**
     * working threads.
     */
    std::vector<std::thread> workThreads_;

    /**
     * enqueue event working mutual exclusion
     */
    std::atomic_flag queueEventAtomicFlag_ = ATOMIC_FLAG_INIT;

    std::atomic_flag queueEventAtomicFlagExtra_ = ATOMIC_FLAG_INIT;

    /**
     * daemon threads wait mtx.
     */
    std::mutex daemonWaitMtx_;

    /**
     * daemon threads reschedule interval
     */
    uint32_t reschedInterval_;

    /**
     * qs run mode
     */
    bqs::QueueSchedulerRunMode runMode_;

    /**
     * group name send by tsd used for qs to attach when start
     */
    std::string qsInitGroupName_;

    /**
     * queue schedule initialization parameters
     */
    InitQsParams initQsParams_;

    /**
     * f2nf event working mutual exclusion
     */
    std::atomic_flag f2nfEventAtomicFlag_ = ATOMIC_FLAG_INIT;

    bool aicpuFeatureDisableRecvRequestEvent_{false};

    bool aicpuFeatureSetPidPriority_{false};

    uint32_t abnormalInterval_;
};
} // namespace bqs
#endif // QUEUE_SCHEDULE_BQS_QUEUE_SCHEDULE_H