/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef TASK_SCHEDULER_H
#define TASK_SCHEDULER_H

#include <cinttypes>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <queue>

#include "i_task_scheduler.h"
#include "id_factory.h"
#include "include/util.h"

namespace OHOS {
namespace Msdp {
namespace DeviceStatus {
class TaskScheduler final : public ITaskScheduler,
                            public IdFactory<int32_t> {
public:
    struct TaskData {
        uint64_t tid { 0 };
        int32_t taskId { 0 };
    };
    class Task : public std::enable_shared_from_this<Task> {
    public:
        using Promise = std::promise<int32_t>;
        using Future = std::future<int32_t>;
        using TaskPtr = std::shared_ptr<TaskScheduler::Task>;
        Task(int32_t id, DTaskCallback fun, Promise *promise = nullptr)
            : id_(id), fun_(fun), promise_(promise) {}
        ~Task() = default;

        TaskPtr GetSharedPtr()
        {
            return shared_from_this();
        }
        int32_t GetId() const
        {
            return id_;
        }
        void SetWaited()
        {
            hasWaited_ = true;
        }
        void ProcessTask();

    private:
        int32_t id_ { 0 };
        std::atomic_bool hasWaited_ { false };
        DTaskCallback fun_ { nullptr };
        Promise* promise_ { nullptr };
    };
    using TaskPtr = Task::TaskPtr;
    using Promise = Task::Promise;
    using Future = Task::Future;

public:
    TaskScheduler() = default;
    ~TaskScheduler();

    bool Init();
    void ProcessTasks();
    int32_t PostSyncTask(DTaskCallback cb) override;
    int32_t PostAsyncTask(DTaskCallback callback) override;

    int32_t GetReadFd() const
    {
        return fds_[0];
    }
    void SetWorkerThreadId(uint64_t tid)
    {
        workerThreadId_ = tid;
    }
    bool IsCallFromWorkerThread() const
    {
        return (GetThisThreadId() == workerThreadId_);
    }

private:
    void PopPendingTaskList(std::vector<TaskPtr> &tasks);
    TaskPtr PostTask(DTaskCallback callback, Promise *promise = nullptr);

private:
    std::atomic<uint64_t> workerThreadId_ { 0 };
    int32_t fds_[2] {};
    std::mutex mux_;
    std::queue<TaskPtr> tasks_;
};
} // namespace DeviceStatus
} // namespace Msdp
} // namespace OHOS
#endif // TASK_SCHEDULER_H