// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/inspector/custom-preview.h"

#include "src/debug/debug-interface.h"
#include "src/inspector/injected-script.h"
#include "src/inspector/inspected-context.h"
#include "src/inspector/string-util.h"
#include "src/inspector/v8-console-message.h"
#include "src/inspector/v8-inspector-impl.h"
#include "src/inspector/v8-stack-trace-impl.h"

namespace v8_inspector {

using protocol::Runtime::CustomPreview;

namespace {
void reportError(v8::Local<v8::Context> context, const v8::TryCatch& tryCatch) {
  DCHECK(tryCatch.HasCaught());
  v8::Isolate* isolate = context->GetIsolate();
  V8InspectorImpl* inspector =
      static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate));
  int contextId = InspectedContext::contextId(context);
  int groupId = inspector->contextGroupId(contextId);
  v8::Local<v8::String> message = tryCatch.Message()->Get();
  v8::Local<v8::String> prefix =
      toV8String(isolate, "Custom Formatter Failed: ");
  message = v8::String::Concat(isolate, prefix, message);
  std::vector<v8::Local<v8::Value>> arguments;
  arguments.push_back(message);
  V8ConsoleMessageStorage* storage =
      inspector->ensureConsoleMessageStorage(groupId);
  if (!storage) return;
  storage->addMessage(V8ConsoleMessage::createForConsoleAPI(
      context, contextId, groupId, inspector,
      inspector->client()->currentTimeMS(), ConsoleAPIType::kError, arguments,
      String16(), nullptr));
}

void reportError(v8::Local<v8::Context> context, const v8::TryCatch& tryCatch,
                 const String16& message) {
  v8::Isolate* isolate = context->GetIsolate();
  isolate->ThrowException(toV8String(isolate, message));
  reportError(context, tryCatch);
}

InjectedScript* getInjectedScript(v8::Local<v8::Context> context,
                                  int sessionId) {
  v8::Isolate* isolate = context->GetIsolate();
  V8InspectorImpl* inspector =
      static_cast<V8InspectorImpl*>(v8::debug::GetInspector(isolate));
  InspectedContext* inspectedContext =
      inspector->getContext(InspectedContext::contextId(context));
  if (!inspectedContext) return nullptr;
  return inspectedContext->getInjectedScript(sessionId);
}

bool substituteObjectTags(int sessionId, const String16& groupName,
                          v8::Local<v8::Context> context,
                          v8::Local<v8::Array> jsonML, int maxDepth) {
  if (!jsonML->Length()) return true;
  v8::Isolate* isolate = context->GetIsolate();
  v8::TryCatch tryCatch(isolate);

  if (maxDepth <= 0) {
    reportError(context, tryCatch,
                "Too deep hierarchy of inlined custom previews");
    return false;
  }

  v8::Local<v8::Value> firstValue;
  if (!jsonML->Get(context, 0).ToLocal(&firstValue)) {
    reportError(context, tryCatch);
    return false;
  }
  v8::Local<v8::String> objectLiteral = toV8String(isolate, "object");
  if (jsonML->Length() == 2 && firstValue->IsString() &&
      firstValue.As<v8::String>()->StringEquals(objectLiteral)) {
    v8::Local<v8::Value> attributesValue;
    if (!jsonML->Get(context, 1).ToLocal(&attributesValue)) {
      reportError(context, tryCatch);
      return false;
    }
    if (!attributesValue->IsObject()) {
      reportError(context, tryCatch, "attributes should be an Object");
      return false;
    }
    v8::Local<v8::Object> attributes = attributesValue.As<v8::Object>();
    v8::Local<v8::Value> originValue;
    if (!attributes->Get(context, objectLiteral).ToLocal(&originValue)) {
      reportError(context, tryCatch);
      return false;
    }
    if (originValue->IsUndefined()) {
      reportError(context, tryCatch,
                  "obligatory attribute \"object\" isn't specified");
      return false;
    }

    v8::Local<v8::Value> configValue;
    if (!attributes->Get(context, toV8String(isolate, "config"))
             .ToLocal(&configValue)) {
      reportError(context, tryCatch);
      return false;
    }

    InjectedScript* injectedScript = getInjectedScript(context, sessionId);
    if (!injectedScript) {
      reportError(context, tryCatch, "cannot find context with specified id");
      return false;
    }
    std::unique_ptr<protocol::Runtime::RemoteObject> wrapper;
    protocol::Response response =
        injectedScript->wrapObject(originValue, groupName, WrapMode::kNoPreview,
                                   configValue, maxDepth - 1, &wrapper);
    if (!response.isSuccess() || !wrapper) {
      reportError(context, tryCatch, "cannot wrap value");
      return false;
    }
    v8::Local<v8::Value> jsonWrapper;
    String16 serialized = wrapper->toJSON();
    if (!v8::JSON::Parse(context, toV8String(isolate, serialized))
             .ToLocal(&jsonWrapper)) {
      reportError(context, tryCatch, "cannot wrap value");
      return false;
    }
    if (jsonML->Set(context, 1, jsonWrapper).IsNothing()) {
      reportError(context, tryCatch);
      return false;
    }
  } else {
    for (uint32_t i = 0; i < jsonML->Length(); ++i) {
      v8::Local<v8::Value> value;
      if (!jsonML->Get(context, i).ToLocal(&value)) {
        reportError(context, tryCatch);
        return false;
      }
      if (value->IsArray() && value.As<v8::Array>()->Length() > 0 &&
          !substituteObjectTags(sessionId, groupName, context,
                                value.As<v8::Array>(), maxDepth - 1)) {
        return false;
      }
    }
  }
  return true;
}

void bodyCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
  v8::Isolate* isolate = info.GetIsolate();
  v8::TryCatch tryCatch(isolate);
  v8::Local<v8::Context> context = isolate->GetCurrentContext();
  v8::Local<v8::Object> bodyConfig = info.Data().As<v8::Object>();

  v8::Local<v8::Value> objectValue;
  if (!bodyConfig->Get(context, toV8String(isolate, "object"))
           .ToLocal(&objectValue)) {
    reportError(context, tryCatch);
    return;
  }
  if (!objectValue->IsObject()) {
    reportError(context, tryCatch, "object should be an Object");
    return;
  }
  v8::Local<v8::Object> object = objectValue.As<v8::Object>();

  v8::Local<v8::Value> formatterValue;
  if (!bodyConfig->Get(context, toV8String(isolate, "formatter"))
           .ToLocal(&formatterValue)) {
    reportError(context, tryCatch);
    return;
  }
  if (!formatterValue->IsObject()) {
    reportError(context, tryCatch, "formatter should be an Object");
    return;
  }
  v8::Local<v8::Object> formatter = formatterValue.As<v8::Object>();

  v8::Local<v8::Value> bodyValue;
  if (!formatter->Get(context, toV8String(isolate, "body"))
           .ToLocal(&bodyValue)) {
    reportError(context, tryCatch);
    return;
  }
  if (!bodyValue->IsFunction()) {
    reportError(context, tryCatch, "body should be a Function");
    return;
  }
  v8::Local<v8::Function> bodyFunction = bodyValue.As<v8::Function>();

  v8::Local<v8::Value> configValue;
  if (!bodyConfig->Get(context, toV8String(isolate, "config"))
           .ToLocal(&configValue)) {
    reportError(context, tryCatch);
    return;
  }

  v8::Local<v8::Value> sessionIdValue;
  if (!bodyConfig->Get(context, toV8String(isolate, "sessionId"))
           .ToLocal(&sessionIdValue)) {
    reportError(context, tryCatch);
    return;
  }
  if (!sessionIdValue->IsInt32()) {
    reportError(context, tryCatch, "sessionId should be an Int32");
    return;
  }

  v8::Local<v8::Value> groupNameValue;
  if (!bodyConfig->Get(context, toV8String(isolate, "groupName"))
           .ToLocal(&groupNameValue)) {
    reportError(context, tryCatch);
    return;
  }
  if (!groupNameValue->IsString()) {
    reportError(context, tryCatch, "groupName should be a string");
    return;
  }

  v8::Local<v8::Value> formattedValue;
  v8::Local<v8::Value> args[] = {object, configValue};
  if (!bodyFunction->Call(context, formatter, 2, args)
           .ToLocal(&formattedValue)) {
    reportError(context, tryCatch);
    return;
  }
  if (!formattedValue->IsArray()) {
    reportError(context, tryCatch, "body should return an Array");
    return;
  }
  v8::Local<v8::Array> jsonML = formattedValue.As<v8::Array>();
  if (jsonML->Length() &&
      !substituteObjectTags(
          sessionIdValue.As<v8::Int32>()->Value(),
          toProtocolString(isolate, groupNameValue.As<v8::String>()), context,
          jsonML, kMaxCustomPreviewDepth)) {
    return;
  }
  info.GetReturnValue().Set(jsonML);
}
}  // anonymous namespace

void generateCustomPreview(int sessionId, const String16& groupName,
                           v8::Local<v8::Context> context,
                           v8::Local<v8::Object> object,
                           v8::MaybeLocal<v8::Value> maybeConfig, int maxDepth,
                           std::unique_ptr<CustomPreview>* preview) {
  v8::Isolate* isolate = context->GetIsolate();
  v8::MicrotasksScope microtasksScope(isolate,
                                      v8::MicrotasksScope::kDoNotRunMicrotasks);
  v8::TryCatch tryCatch(isolate);

  v8::Local<v8::Value> configValue;
  if (!maybeConfig.ToLocal(&configValue)) configValue = v8::Undefined(isolate);

  v8::Local<v8::Object> global = context->Global();
  v8::Local<v8::Value> formattersValue;
  if (!global->Get(context, toV8String(isolate, "devtoolsFormatters"))
           .ToLocal(&formattersValue)) {
    reportError(context, tryCatch);
    return;
  }
  if (!formattersValue->IsArray()) return;
  v8::Local<v8::Array> formatters = formattersValue.As<v8::Array>();
  v8::Local<v8::String> headerLiteral = toV8String(isolate, "header");
  v8::Local<v8::String> hasBodyLiteral = toV8String(isolate, "hasBody");
  for (uint32_t i = 0; i < formatters->Length(); ++i) {
    v8::Local<v8::Value> formatterValue;
    if (!formatters->Get(context, i).ToLocal(&formatterValue)) {
      reportError(context, tryCatch);
      return;
    }
    if (!formatterValue->IsObject()) {
      reportError(context, tryCatch, "formatter should be an Object");
      return;
    }
    v8::Local<v8::Object> formatter = formatterValue.As<v8::Object>();

    v8::Local<v8::Value> headerValue;
    if (!formatter->Get(context, headerLiteral).ToLocal(&headerValue)) {
      reportError(context, tryCatch);
      return;
    }
    if (!headerValue->IsFunction()) {
      reportError(context, tryCatch, "header should be a Function");
      return;
    }
    v8::Local<v8::Function> headerFunction = headerValue.As<v8::Function>();

    v8::Local<v8::Value> formattedValue;
    v8::Local<v8::Value> args[] = {object, configValue};
    if (!headerFunction->Call(context, formatter, 2, args)
             .ToLocal(&formattedValue)) {
      reportError(context, tryCatch);
      return;
    }
    if (!formattedValue->IsArray()) continue;
    v8::Local<v8::Array> jsonML = formattedValue.As<v8::Array>();

    v8::Local<v8::Value> hasBodyFunctionValue;
    if (!formatter->Get(context, hasBodyLiteral)
             .ToLocal(&hasBodyFunctionValue)) {
      reportError(context, tryCatch);
      return;
    }
    if (!hasBodyFunctionValue->IsFunction()) continue;
    v8::Local<v8::Function> hasBodyFunction =
        hasBodyFunctionValue.As<v8::Function>();
    v8::Local<v8::Value> hasBodyValue;
    if (!hasBodyFunction->Call(context, formatter, 2, args)
             .ToLocal(&hasBodyValue)) {
      reportError(context, tryCatch);
      return;
    }
    bool hasBody = hasBodyValue->ToBoolean(isolate)->Value();

    if (jsonML->Length() && !substituteObjectTags(sessionId, groupName, context,
                                                  jsonML, maxDepth)) {
      return;
    }

    v8::Local<v8::String> header;
    if (!v8::JSON::Stringify(context, jsonML).ToLocal(&header)) {
      reportError(context, tryCatch);
      return;
    }

    v8::Local<v8::Function> bodyFunction;
    if (hasBody) {
      v8::Local<v8::Object> bodyConfig = v8::Object::New(isolate);
      if (bodyConfig
              ->CreateDataProperty(context, toV8String(isolate, "sessionId"),
                                   v8::Integer::New(isolate, sessionId))
              .IsNothing()) {
        reportError(context, tryCatch);
        return;
      }
      if (bodyConfig
              ->CreateDataProperty(context, toV8String(isolate, "formatter"),
                                   formatter)
              .IsNothing()) {
        reportError(context, tryCatch);
        return;
      }
      if (bodyConfig
              ->CreateDataProperty(context, toV8String(isolate, "groupName"),
                                   toV8String(isolate, groupName))
              .IsNothing()) {
        reportError(context, tryCatch);
        return;
      }
      if (bodyConfig
              ->CreateDataProperty(context, toV8String(isolate, "config"),
                                   configValue)
              .IsNothing()) {
        reportError(context, tryCatch);
        return;
      }
      if (bodyConfig
              ->CreateDataProperty(context, toV8String(isolate, "object"),
                                   object)
              .IsNothing()) {
        reportError(context, tryCatch);
        return;
      }
      if (!v8::Function::New(context, bodyCallback, bodyConfig)
               .ToLocal(&bodyFunction)) {
        reportError(context, tryCatch);
        return;
      }
    }
    *preview = CustomPreview::create()
                   .setHeader(toProtocolString(isolate, header))
                   .build();
    if (!bodyFunction.IsEmpty()) {
      InjectedScript* injectedScript = getInjectedScript(context, sessionId);
      if (!injectedScript) {
        reportError(context, tryCatch, "cannot find context with specified id");
        return;
      }
      (*preview)->setBodyGetterId(
          injectedScript->bindObject(bodyFunction, groupName));
    }
    return;
  }
}
}  // namespace v8_inspector
