// Copyright 2021 The Dawn Authors
//
// 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 "src/dawn_node/binding/GPUShaderModule.h"

#include <memory>

#include "src/dawn_node/utils/Debug.h"

namespace wgpu::binding {

    ////////////////////////////////////////////////////////////////////////////////
    // wgpu::bindings::GPUShaderModule
    ////////////////////////////////////////////////////////////////////////////////
    GPUShaderModule::GPUShaderModule(wgpu::ShaderModule shader, std::shared_ptr<AsyncRunner> async)
        : shader_(std::move(shader)), async_(std::move(async)) {
    }

    interop::Promise<interop::Interface<interop::GPUCompilationInfo>>
    GPUShaderModule::compilationInfo(Napi::Env env) {
        struct GPUCompilationMessage : public interop::GPUCompilationMessage {
            WGPUCompilationMessage message;

            GPUCompilationMessage(const WGPUCompilationMessage& m) : message(m) {
            }
            std::string getMessage(Napi::Env) override {
                return message.message;
            }
            interop::GPUCompilationMessageType getType(Napi::Env) override {
                switch (message.type) {
                    case WGPUCompilationMessageType_Error:
                        return interop::GPUCompilationMessageType::kError;
                    case WGPUCompilationMessageType_Warning:
                        return interop::GPUCompilationMessageType::kWarning;
                    case WGPUCompilationMessageType_Info:
                        return interop::GPUCompilationMessageType::kInfo;
                    default:
                        UNIMPLEMENTED();
                }
            }
            uint64_t getLineNum(Napi::Env) override {
                return message.lineNum;
            }
            uint64_t getLinePos(Napi::Env) override {
                return message.linePos;
            }
            uint64_t getOffset(Napi::Env) override {
                return message.offset;
            }
            uint64_t getLength(Napi::Env) override {
                return message.length;
            }
        };

        using Messages = std::vector<interop::Interface<interop::GPUCompilationMessage>>;

        struct GPUCompilationInfo : public interop::GPUCompilationInfo {
            std::vector<Napi::ObjectReference> messages;

            GPUCompilationInfo(Napi::Env env, Messages msgs) {
                messages.reserve(msgs.size());
                for (auto& msg : msgs) {
                    messages.emplace_back(Napi::Persistent(Napi::Object(env, msg)));
                }
            }
            Messages getMessages(Napi::Env) override {
                Messages out;
                out.reserve(messages.size());
                for (auto& msg : messages) {
                    out.emplace_back(msg.Value());
                }
                return out;
            }
        };

        using Promise = interop::Promise<interop::Interface<interop::GPUCompilationInfo>>;

        struct Context {
            Napi::Env env;
            Promise promise;
            AsyncTask task;
        };
        auto ctx = new Context{env, Promise(env, PROMISE_INFO), async_};
        auto promise = ctx->promise;

        shader_.GetCompilationInfo(
            [](WGPUCompilationInfoRequestStatus status, WGPUCompilationInfo const* compilationInfo,
               void* userdata) {
                auto c = std::unique_ptr<Context>(static_cast<Context*>(userdata));

                Messages messages(compilationInfo->messageCount);
                for (uint32_t i = 0; i < compilationInfo->messageCount; i++) {
                    auto& msg = compilationInfo->messages[i];
                    messages[i] =
                        interop::GPUCompilationMessage::Create<GPUCompilationMessage>(c->env, msg);
                }

                c->promise.Resolve(interop::GPUCompilationInfo::Create<GPUCompilationInfo>(
                    c->env, c->env, std::move(messages)));
            },
            ctx);

        return promise;
    }

    std::optional<std::string> GPUShaderModule::getLabel(Napi::Env) {
        UNIMPLEMENTED();
    }

    void GPUShaderModule::setLabel(Napi::Env, std::optional<std::string> value) {
        UNIMPLEMENTED();
    }

}  // namespace wgpu::binding
