// 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/GPUBuffer.h"

#include <memory>

#include "src/dawn/node/binding/Converter.h"
#include "src/dawn/node/binding/Errors.h"
#include "src/dawn/node/utils/Debug.h"

namespace wgpu::binding {

    ////////////////////////////////////////////////////////////////////////////////
    // wgpu::bindings::GPUBuffer
    // TODO(crbug.com/dawn/1134): We may be doing more validation here than necessary. Once CTS is
    // robustly passing, pull out validation and see what / if breaks.
    ////////////////////////////////////////////////////////////////////////////////
    GPUBuffer::GPUBuffer(wgpu::Buffer buffer,
                         wgpu::BufferDescriptor desc,
                         wgpu::Device device,
                         std::shared_ptr<AsyncRunner> async)
        : buffer_(std::move(buffer)),
          desc_(desc),
          device_(std::move(device)),
          async_(std::move(async)) {
        if (desc.mappedAtCreation) {
            state_ = State::MappedAtCreation;
        }
    }

    interop::Promise<void> GPUBuffer::mapAsync(Napi::Env env,
                                               interop::GPUMapModeFlags mode,
                                               interop::GPUSize64 offset,
                                               std::optional<interop::GPUSize64> size) {
        wgpu::MapMode md{};
        Converter conv(env);
        if (!conv(md, mode)) {
            interop::Promise<void> promise(env, PROMISE_INFO);
            promise.Reject(Errors::OperationError(env));
            return promise;
        }

        if (state_ != State::Unmapped) {
            interop::Promise<void> promise(env, PROMISE_INFO);
            promise.Reject(Errors::OperationError(env));
            device_.InjectError(wgpu::ErrorType::Validation,
                                "mapAsync called on buffer that is not in the unmapped state");
            return promise;
        }

        struct Context {
            Napi::Env env;
            interop::Promise<void> promise;
            AsyncTask task;
            State& state;
        };
        auto ctx = new Context{env, interop::Promise<void>(env, PROMISE_INFO), async_, state_};
        auto promise = ctx->promise;

        uint64_t s = size.has_value() ? size.value().value : (desc_.size - offset);

        state_ = State::MappingPending;

        buffer_.MapAsync(
            md, offset, s,
            [](WGPUBufferMapAsyncStatus status, void* userdata) {
                auto c = std::unique_ptr<Context>(static_cast<Context*>(userdata));
                c->state = State::Unmapped;
                switch (status) {
                    case WGPUBufferMapAsyncStatus_Force32:
                        UNREACHABLE("WGPUBufferMapAsyncStatus_Force32");
                        break;
                    case WGPUBufferMapAsyncStatus_Success:
                        c->promise.Resolve();
                        c->state = State::Mapped;
                        break;
                    case WGPUBufferMapAsyncStatus_Error:
                        c->promise.Reject(Errors::OperationError(c->env));
                        break;
                    case WGPUBufferMapAsyncStatus_UnmappedBeforeCallback:
                    case WGPUBufferMapAsyncStatus_DestroyedBeforeCallback:
                        c->promise.Reject(Errors::AbortError(c->env));
                        break;
                    case WGPUBufferMapAsyncStatus_Unknown:
                    case WGPUBufferMapAsyncStatus_DeviceLost:
                        // TODO: The spec is a bit vague around what the promise should do
                        // here.
                        c->promise.Reject(Errors::UnknownError(c->env));
                        break;
                }
            },
            ctx);

        return promise;
    }

    interop::ArrayBuffer GPUBuffer::getMappedRange(Napi::Env env,
                                                   interop::GPUSize64 offset,
                                                   std::optional<interop::GPUSize64> size) {
        if (state_ != State::Mapped && state_ != State::MappedAtCreation) {
            Errors::OperationError(env).ThrowAsJavaScriptException();
            return {};
        }

        uint64_t s = size.has_value() ? size.value().value : (desc_.size - offset);

        uint64_t start = offset;
        uint64_t end = offset + s;
        for (auto& mapping : mapped_) {
            if (mapping.Intersects(start, end)) {
                Errors::OperationError(env).ThrowAsJavaScriptException();
                return {};
            }
        }

        auto* ptr = (desc_.usage & wgpu::BufferUsage::MapWrite)
                        ? buffer_.GetMappedRange(offset, s)
                        : const_cast<void*>(buffer_.GetConstMappedRange(offset, s));
        if (!ptr) {
            Errors::OperationError(env).ThrowAsJavaScriptException();
            return {};
        }
        auto array_buffer = Napi::ArrayBuffer::New(env, ptr, s);
        // TODO(crbug.com/dawn/1135): Ownership here is the wrong way around.
        mapped_.emplace_back(Mapping{start, end, Napi::Persistent(array_buffer)});
        return array_buffer;
    }

    void GPUBuffer::unmap(Napi::Env env) {
        buffer_.Unmap();

        if (state_ != State::Destroyed && state_ != State::Unmapped) {
            DetachMappings();
            state_ = State::Unmapped;
        }
    }

    void GPUBuffer::destroy(Napi::Env) {
        if (state_ == State::Destroyed) {
            return;
        }

        if (state_ != State::Unmapped) {
            DetachMappings();
        }

        buffer_.Destroy();
        state_ = State::Destroyed;
    }

    void GPUBuffer::DetachMappings() {
        for (auto& mapping : mapped_) {
            mapping.buffer.Value().Detach();
        }
        mapped_.clear();
    }

    std::variant<std::string, interop::UndefinedType> GPUBuffer::getLabel(Napi::Env) {
        UNIMPLEMENTED();
    }

    void GPUBuffer::setLabel(Napi::Env, std::variant<std::string, interop::UndefinedType> value) {
        UNIMPLEMENTED();
    }

}  // namespace wgpu::binding
