/**

 * 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.

 */



#include <vector>

#include "api_c.h"

#include "api.hpp"

#include "api_handle_guard.h"

#include "osal.hpp"

#include "thread_local_container.hpp"

#include "rts/rts.h"

#include "global_state_manager.hpp"

#include "api_handle_guard.h"

#include "label.hpp"

#include "model.hpp"

#include "runtime.hpp"

#include "stream.hpp"

#include "rt_external_model.h"



using namespace cce::runtime;



#ifdef __cplusplus

extern "C" {

#endif // __cplusplus



VISIBILITY_DEFAULT

rtError_t rtModelCreate(rtModel_t* mdl, uint32_t flag)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    const rtError_t error = apiInstance->ModelCreate(RtPtrToPtr<Model**>(mdl), flag);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    Model* realModel = RtPtrToPtr<Model*>(*mdl);

    *mdl = ExportEmbeddedHandle<rtModel_t>(realModel);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtModelAddHcclStream(rtStream_t stream, rtModel_t mdl)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    const Runtime* const rtInstance = Runtime::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(rtInstance);

    Api* const api = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(api);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, modelObj);

    RT_VALIDATE_AND_UNWRAP_OBJECT(stream, Stream, streamObj);

    const rtError_t error = api->HcclStreamAddToModel(streamObj, modelObj);

    COND_RETURN_WITH_NOLOG(error == RT_ERROR_FEATURE_NOT_SUPPORT, ACL_ERROR_RT_FEATURE_NOT_SUPPORT);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtModelGetHcclStream(rtModel_t mdl, rtStream_t* streams, uint32_t* numStreams)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    PARAM_NULL_RETURN_ERROR_WITH_EXT_ERRCODE(numStreams, RT_ERROR_INVALID_VALUE);

    Api* const api = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(api);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, modelObj);

    std::vector<Stream*> hcclStreams;

    const rtError_t error = api->ModelGetHcclStream(modelObj, hcclStreams);

    COND_RETURN_WITH_NOLOG(error == RT_ERROR_FEATURE_NOT_SUPPORT, ACL_ERROR_RT_FEATURE_NOT_SUPPORT);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    const uint32_t required = static_cast<uint32_t>(hcclStreams.size());

    if (streams == nullptr) {

        *numStreams = required;

        return ACL_RT_SUCCESS;

    }

    const uint32_t capacity = *numStreams;

    COND_RETURN_AND_MSG_OUTER(

        capacity < required, GetRtExtErrCodeAndSetGlobalErr(RT_ERROR_INSUFFICIENT_INPUT_ARRAY), ErrorCode::EE1011,

        "Obtaining HCCL streams registered with a model", capacity, "numStreams",

        RtFmtMsg(

            "The array space is insufficient for the HCCL streams registered with model (model_id=%u). "

            "Required capacity is %u",

            modelObj->Id_(), required));

    for (uint32_t i = 0U; i < required; ++i) {

        streams[i] = ExportEmbeddedHandle<rtStream_t>(hcclStreams[i]);

    }

    *numStreams = required;

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtGetModelByStream(rtStream_t stream, rtModel_t* mdl)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    Api* const api = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(api);

    RT_VALIDATE_AND_UNWRAP_OBJECT(stream, Stream, streamObj);

    const rtError_t error = api->GetModelByStream(streamObj, RtPtrToPtr<Model**>(mdl));

    COND_RETURN_WITH_NOLOG(error == RT_ERROR_FEATURE_NOT_SUPPORT, ACL_ERROR_RT_FEATURE_NOT_SUPPORT);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    Model* const realModel = RtPtrToPtr<Model*>(*mdl);

    *mdl = ExportEmbeddedHandle<rtModel_t>(realModel);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtSetModelName(rtModel_t mdl, const char_t* mdlName)

{

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, realModel);

    const rtError_t error = apiInstance->ModelNameSet(realModel, mdlName);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtModelExecuteSync(rtModel_t mdl, rtStream_t stm, uint32_t flag, int32_t timeout)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, realModel);

    RT_VALIDATE_AND_UNWRAP_OBJECT(stm, Stream, exeStream);

    const rtError_t error = apiInstance->ModelExecute(realModel, exeStream, flag, timeout);

    COND_RETURN_WITH_NOLOG(error == RT_ERROR_FEATURE_NOT_SUPPORT, ACL_ERROR_RT_FEATURE_NOT_SUPPORT);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsModelCreate(rtModel_t* mdl, uint32_t flag)

{

    COND_RETURN_AND_MSG_OUTER_WITH_PARAM((flag != 0), ACL_ERROR_RT_PARAM_INVALID, flag, "0");

    return rtModelCreate(mdl, flag);

}



VISIBILITY_DEFAULT

rtError_t rtsModelBindStream(rtModel_t mdl, rtStream_t stm, uint32_t flag)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    COND_RETURN_AND_MSG_OUTER_WITH_PARAM(

        ((flag != RT_MODEL_STREAM_FLAG_HEAD) && (flag != RT_MODEL_STREAM_FLAG_DEFAULT)), ACL_ERROR_RT_PARAM_INVALID,

        flag, "RT_MODEL_STREAM_FLAG_HEAD or RT_MODEL_STREAM_FLAG_DEFAULT");

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, realModel);

    RT_VALIDATE_AND_UNWRAP_OBJECT(stm, Stream, bindStream);

    COND_RETURN_EXT_ERRCODE_AND_MSG_OUTER(

        (bindStream != nullptr) && ((bindStream->Flags() & RT_STREAM_PERSISTENT) == 0), RT_ERROR_INVALID_VALUE,

        ErrorCode::EE1017, __func__, "stm", "Non-persistent stream cannot be bound to a model");

    if ((bindStream != nullptr) && bindStream->IsModelStream()) {

        const Model* const bindModel = bindStream->Model_();

        RT_LOG_OUTER_MSG_IMPL(

            ErrorCode::EE1007, bindStream->Id_(),

            RtFmtMsg(

                "The current stream has been bound to a model (model_id=%u) and cannot be bound to the input model "

                "(model_id=%u)",

                (bindModel == nullptr) ? UINT32_MAX : bindModel->Id_(), realModel->Id_()));

        return GetRtExtErrCodeAndSetGlobalErr(RT_ERROR_STREAM_MODEL);

    }



    rtError_t error = apiInstance->ModelBindStream(realModel, bindStream, flag);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    error = apiInstance->SetStreamSqLockUnlock(bindStream, true);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsEndGraph(rtModel_t mdl, rtStream_t stm)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, realModel);

    RT_VALIDATE_AND_UNWRAP_OBJECT(stm, Stream, exeStream);

    rtError_t error = apiInstance->SetStreamSqLockUnlock(exeStream, false);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    error = apiInstance->ModelEndGraph(realModel, exeStream, 0U);

    COND_RETURN_EXT_ERRCODE_AND_MSG_OUTER(

        (error == RT_ERROR_DRV_NO_NOTIFY_RESOURCES) || (error == RT_ERROR_DRV_NO_RESOURCES), error, ErrorCode::EE1023,

        __func__, "Too many Notify objects are created");

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsModelLoadComplete(rtModel_t mdl, void* reserve)

{

    COND_RETURN_AND_MSG_OUTER_WITH_PARAM((reserve != nullptr), ACL_ERROR_RT_PARAM_INVALID, reserve, "nullptr");

    return rtModelLoadComplete(mdl);

}



VISIBILITY_DEFAULT

rtError_t rtsModelUnbindStream(rtModel_t mdl, rtStream_t stm) { return rtModelUnbindStream(mdl, stm); }



VISIBILITY_DEFAULT

rtError_t rtsModelDestroy(rtModel_t mdl) { return rtModelDestroy(mdl); }



VISIBILITY_DEFAULT

rtError_t rtsModelExecute(rtModel_t mdl, int32_t timeout)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, realModel);

    const rtError_t error = apiInstance->ModelExecuteSync(realModel, timeout);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsModelExecuteAsync(rtModel_t mdl, rtStream_t stm)

{

    GLOBAL_STATE_WAIT_IF_LOCKED();

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, realModel);

    RT_VALIDATE_AND_UNWRAP_OBJECT(stm, Stream, exeStream);

    const rtError_t error = apiInstance->ModelExecuteAsync(realModel, exeStream);

    COND_RETURN_WITH_NOLOG(error == RT_ERROR_FEATURE_NOT_SUPPORT, ACL_ERROR_RT_FEATURE_NOT_SUPPORT);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsLabelCreate(rtLabel_t* lbl)

{

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    const rtError_t error = apiInstance->LabelCreate(RtPtrToPtr<Label**>(lbl), nullptr);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    Label* realLabel = RtPtrToPtr<Label*>(*lbl);

    *lbl = ExportEmbeddedHandle<rtLabel_t>(realLabel);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsLabelDestroy(rtLabel_t lbl) { return rtLabelDestroy(lbl); }



VISIBILITY_DEFAULT

rtError_t rtsLabelSwitchListCreate(rtLabel_t* labels, size_t num, void** labelList)

{

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    COND_RETURN_EXT_ERRCODE_AND_MSG_OUTER_WITH_PARAM(

        ((num == 0U) || (num > static_cast<size_t>(MAX_UINT16_NUM))), RT_ERROR_INVALID_VALUE, num,

        RtFmtMsg("(0, %u]", MAX_UINT16_NUM));

    RT_VALIDATE_AND_UNWRAP_OBJECT_ARRAY(labels, num, Label, realLabels);

    const rtError_t error = apiInstance->LabelSwitchListCreate(realLabels.data(), num, labelList);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsLabelSwitchListDestroy(void* labelList) { return rtsFree(labelList); }



VISIBILITY_DEFAULT

rtError_t rtsLabelSet(rtLabel_t lbl, rtStream_t stm) { return rtLabelSet(lbl, stm); }



VISIBILITY_DEFAULT

rtError_t rtsLabelSwitchByIndex(void* ptr, uint32_t maxValue, void* labelInfoPtr, rtStream_t stm)

{

    return rtLabelSwitchByIndex(ptr, maxValue, labelInfoPtr, stm);

}



VISIBILITY_DEFAULT

rtError_t rtsModelSetName(rtModel_t mdl, const char_t* mdlName) { return rtSetModelName(mdl, mdlName); }



VISIBILITY_DEFAULT

rtError_t rtsModelGetName(rtModel_t mdl, const uint32_t maxLen, char_t* const mdlName)

{

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, realModel);

    const rtError_t error = apiInstance->ModelGetName(realModel, maxLen, mdlName);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsModelGetId(rtModel_t mdl, uint32_t* modelId) { return rtModelGetId(mdl, modelId); }



VISIBILITY_DEFAULT

rtError_t rtsSetModelAttr(rtModel_t mdl, rtModelAttr modelAttrId, void* value)

{

    Api* const apiInstance = Api::Instance();

    NULL_RETURN_ERROR_WITH_EXT_ERRCODE(apiInstance);

    RT_VALIDATE_AND_UNWRAP_OBJECT(mdl, Model, realModel);



    const rtError_t error = apiInstance->ModelAttrSet(realModel, modelAttrId, value);

    ERROR_RETURN_WITH_EXT_ERRCODE(error);

    return ACL_RT_SUCCESS;

}



VISIBILITY_DEFAULT

rtError_t rtsModelAbort(rtModel_t mdl) { return rtModelAbort(mdl); }



#ifdef __cplusplus

}

#endif // __cplusplus