/**
 * Copyright (c) 2025-2026 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.
 */

#include "common.h"

#include "panda_types.h"
#include "public/es2panda_lib.h"

// NOLINTBEGIN
inline KUInt UnpackUInt(const KByte *bytes)
{
    const KUInt oneByte = 8U;
    const KUInt twoByte = 16U;
    const KUInt threeByte = 24U;
    return (static_cast<KUInt>(bytes[0]) | (static_cast<KUInt>(bytes[1]) << oneByte) |
            (static_cast<KUInt>(bytes[twoByte / oneByte]) << twoByte) |
            (static_cast<KUInt>(bytes[threeByte / oneByte]) << threeByte));
}
// NOLINTEND

KNativePointer impl_ProceedToState(KNativePointer contextPtr, KInt state)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    return GetPublicImpl()->ProceedToState(context, es2panda_ContextState(state));
}
TS_INTEROP_2(ProceedToState, KNativePointer, KNativePointer, KInt)

KNativePointer impl_ContextProgram(KNativePointer contextPtr)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    return GetPublicImpl()->ContextProgram(context);
}
TS_INTEROP_1(ContextProgram, KNativePointer, KNativePointer)

KNativePointer impl_ProgramExternalSources(KNativePointer contextPtr, [[maybe_unused]] KNativePointer programPtr,
                                           KNativePointer lenPtr)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    auto lenP = reinterpret_cast<std::size_t *>(lenPtr);
    return GetPublicImpl()->ProgramExternalSources(context, nullptr, lenP);
}
TS_INTEROP_3(ProgramExternalSources, KNativePointer, KNativePointer, KNativePointer, KNativePointer)

KNativePointer impl_CreateCacheContextFromFile(KNativePointer configPtr, KStringPtr &sourceFileName,
                                               KNativePointer globalContext, KBoolean isExternal)
{
    auto config = reinterpret_cast<es2panda_Config *>(configPtr);
    auto context = reinterpret_cast<es2panda_GlobalContext *>(globalContext);
    return GetPublicImpl()->CreateCacheContextFromFile(config, sourceFileName.Data(), context, isExternal != 0);
}
TS_INTEROP_4(CreateCacheContextFromFile, KNativePointer, KNativePointer, KStringPtr, KNativePointer, KBoolean)

KNativePointer impl_CreateContextFromString(KNativePointer configPtr, KStringPtr &sourcePtr, KStringPtr &filenamePtr)
{
    auto config = reinterpret_cast<es2panda_Config *>(configPtr);
    return GetPublicImpl()->CreateContextFromString(config, sourcePtr.Data(), filenamePtr.Data());
}
TS_INTEROP_3(CreateContextFromString, KNativePointer, KNativePointer, KStringPtr, KStringPtr)

KNativePointer impl_CreateContextFromStringWithHistory(KNativePointer configPtr, KStringPtr &sourcePtr,
                                                       KStringPtr &filenamePtr)
{
    auto config = reinterpret_cast<es2panda_Config *>(configPtr);
    return GetPublicImpl()->CreateContextFromStringWithHistory(config, sourcePtr.Data(), filenamePtr.Data());
}
TS_INTEROP_3(CreateContextFromStringWithHistory, KNativePointer, KNativePointer, KStringPtr, KStringPtr)

KNativePointer impl_CreateTsDeclgen(KNativePointer contextPtr, KUInt fileNamesCount, KStringArray inputFiles,
                                    KStringArray outputDeclEts, KStringArray outputEts, KBoolean exportAll,
                                    KBoolean isolated, KStringPtr &recordFile, KBoolean genAnnotations)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    const std::size_t headerLen = 4;

    const auto count = static_cast<std::size_t>(fileNamesCount);
    std::vector<std::string> inputFilesStr;
    std::vector<std::string> outputDeclEtsStr;
    std::vector<std::string> outputEtsStr;
    inputFilesStr.reserve(count);
    outputDeclEtsStr.reserve(count);
    outputEtsStr.reserve(count);

    std::size_t inputPosition = headerLen;
    std::size_t declPosition = headerLen;
    std::size_t etsPosition = headerLen;

    for (std::size_t i = 0; i < count; ++i) {
        std::size_t strLen = UnpackUInt(inputFiles + inputPosition);
        inputPosition += headerLen;
        inputFilesStr.emplace_back(reinterpret_cast<const char *>(inputFiles + inputPosition), strLen);
        inputPosition += strLen;

        strLen = UnpackUInt(outputDeclEts + declPosition);
        declPosition += headerLen;
        outputDeclEtsStr.emplace_back(reinterpret_cast<const char *>(outputDeclEts + declPosition), strLen);
        declPosition += strLen;

        strLen = UnpackUInt(outputEts + etsPosition);
        etsPosition += headerLen;
        outputEtsStr.emplace_back(reinterpret_cast<const char *>(outputEts + etsPosition), strLen);
        etsPosition += strLen;
    }

    std::vector<const char *> inputFilesList(count);
    std::vector<const char *> outputDeclEtsList(count);
    std::vector<const char *> outputEtsList(count);
    for (std::size_t i = 0; i < count; ++i) {
        inputFilesList[i] = inputFilesStr[i].c_str();
        outputDeclEtsList[i] = outputDeclEtsStr[i].c_str();
        outputEtsList[i] = outputEtsStr[i].c_str();
    }

    return static_cast<KNativePointer>(GetPublicImpl()->CreateTsDeclgen(
        context, fileNamesCount, inputFilesList.data(), outputDeclEtsList.data(), outputEtsList.data(), exportAll != 0,
        isolated != 0, recordFile.Data(), genAnnotations != 0));
}
TS_INTEROP_9(CreateTsDeclgen, KNativePointer, KNativePointer, KUInt, KStringArray, KStringArray, KStringArray, KBoolean,
             KBoolean, KStringPtr, KBoolean)

KInt impl_GenerateTsDeclarationsAfterParsed(KNativePointer declgenPtr)
{
    auto declgen = reinterpret_cast<es2panda_TsDeclgen *>(declgenPtr);
    return static_cast<KInt>(GetPublicImpl()->GenerateTsDeclarationsAfterParsed(declgen));
}
TS_INTEROP_1(GenerateTsDeclarationsAfterParsed, KInt, KNativePointer)

KInt impl_GenerateTsDeclarationsAfterCheck(KNativePointer declgenPtr)
{
    auto declgen = reinterpret_cast<es2panda_TsDeclgen *>(declgenPtr);
    return static_cast<KInt>(GetPublicImpl()->GenerateTsDeclarationsAfterCheck(declgen));
}
TS_INTEROP_1(GenerateTsDeclarationsAfterCheck, KInt, KNativePointer)

KInt impl_WriteTsDeclarations(KNativePointer declgenPtr)
{
    auto declgen = reinterpret_cast<es2panda_TsDeclgen *>(declgenPtr);
    return static_cast<KInt>(GetPublicImpl()->WriteTsDeclarations(declgen));
}
TS_INTEROP_1(WriteTsDeclarations, KInt, KNativePointer)

void impl_DestroyTsDeclgen(KNativePointer declgenPtr)
{
    auto declgen = reinterpret_cast<es2panda_TsDeclgen *>(declgenPtr);
    GetPublicImpl()->DestroyTsDeclgen(declgen);
}
TS_INTEROP_V1(DestroyTsDeclgen, KNativePointer)

KNativePointer impl_FormOutputPathForFile(KNativePointer contextPtr, KStringPtr &inputPath)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    return new std::string(GetPublicImpl()->FormOutputPathForFile(context, GetStringCopy(inputPath)));
}
TS_INTEROP_2(FormOutputPathForFile, KNativePointer, KNativePointer, KStringPtr)

KNativePointer impl_CreateContextSimultaneousModeForLsp(KNativePointer configPtr, KInt fileNamesCount,
                                                        KStringArray filenames, KBoolean isLspUsage)
{
    auto config = reinterpret_cast<es2panda_Config *>(configPtr);
    const std::size_t headerLen = 4;
    if (fileNamesCount <= 0) {
        return nullptr;
    }
    const char **externalFileList = new const char *[fileNamesCount];
    std::size_t position = headerLen;
    std::size_t strLen;
    for (std::size_t i = 0; i < static_cast<std::size_t>(fileNamesCount); ++i) {
        strLen = UnpackUInt(filenames + position);
        position += headerLen;
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
        externalFileList[i] = strdup(std::string(reinterpret_cast<const char *>(filenames + position), strLen).c_str());
        position += strLen;
    }
    return GetPublicImpl()->CreateContextSimultaneousModeForLsp(config, fileNamesCount, externalFileList,
                                                                isLspUsage != 0);
}
TS_INTEROP_4(CreateContextSimultaneousModeForLsp, KNativePointer, KNativePointer, KInt, KStringArray, KBoolean)

KNativePointer impl_CreateContextSimultaneousMode(KNativePointer configPtr, KInt fileNamesCount, KStringArray filenames)
{
    auto config = reinterpret_cast<es2panda_Config *>(configPtr);
    const std::size_t headerLen = 4;
    if (fileNamesCount <= 0) {
        return nullptr;
    }
    const char **externalFileList = new const char *[fileNamesCount];
    std::size_t position = headerLen;
    std::size_t strLen;
    for (std::size_t i = 0; i < static_cast<std::size_t>(fileNamesCount); ++i) {
        strLen = UnpackUInt(filenames + position);
        position += headerLen;
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
        externalFileList[i] = strdup(std::string(reinterpret_cast<const char *>(filenames + position), strLen).c_str());
        position += strLen;
    }
    return GetPublicImpl()->CreateContextSimultaneousMode(config, fileNamesCount, externalFileList);
}
TS_INTEROP_3(CreateContextSimultaneousMode, KNativePointer, KNativePointer, KInt, KStringArray)

KInt impl_GenerateStaticDeclarationsFromContext(KNativePointer contextPtr, KStringPtr &outputPath)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    return static_cast<KInt>(
        GetPublicImpl()->GenerateStaticDeclarationsFromContext(context, GetStringCopy(outputPath)));
}
TS_INTEROP_2(GenerateStaticDeclarationsFromContext, KInt, KNativePointer, KStringPtr)

KNativePointer impl_CreateContextFromFile(KNativePointer configPtr, KStringPtr &filenamePtr)
{
    auto config = reinterpret_cast<es2panda_Config *>(configPtr);
    return GetPublicImpl()->CreateContextFromFile(config, GetStringCopy(filenamePtr));
}
TS_INTEROP_2(CreateContextFromFile, KNativePointer, KNativePointer, KStringPtr)

KInt impl_ContextState(KNativePointer contextPtr)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    return static_cast<KInt>(GetPublicImpl()->ContextState(context));
}
TS_INTEROP_1(ContextState, KInt, KNativePointer)

KNativePointer impl_ContextErrorMessage(KNativePointer contextPtr)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    return new std::string(GetPublicImpl()->ContextErrorMessage(context));
}
TS_INTEROP_1(ContextErrorMessage, KNativePointer, KNativePointer)

KNativePointer impl_GetAllErrorMessages(KNativePointer contextPtr)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    return new std::string(GetPublicImpl()->GetAllErrorMessages(context));
}
TS_INTEROP_1(GetAllErrorMessages, KNativePointer, KNativePointer)

KNativePointer impl_ProgramAst(KNativePointer contextPtr, KNativePointer programPtr)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    auto program = reinterpret_cast<es2panda_Program *>(programPtr);
    return GetPublicImpl()->ProgramAst(context, program);
}
TS_INTEROP_2(ProgramAst, KNativePointer, KNativePointer, KNativePointer)

KNativePointer impl_FreeCompilerPartMemory(KNativePointer contextPtr)
{
    auto context = reinterpret_cast<es2panda_Context *>(contextPtr);
    GetPublicImpl()->FreeCompilerPartMemory(context);
    return nullptr;
}
TS_INTEROP_1(FreeCompilerPartMemory, KNativePointer, KNativePointer)

KInt impl_ExtractDeclarationsFromAbcFile(KStringPtr &abcFile, KStringPtr &cacheDir)
{
    return GetPublicImpl()->ExtractDeclarationsFromAbcFile(abcFile.Data(), cacheDir.Data());
}
TS_INTEROP_2(ExtractDeclarationsFromAbcFile, KInt, KStringPtr, KStringPtr)