/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 <dlpack/dlpack.h>
#include <gtest/gtest.h>

#include <map>
#include <random>
#include <vector>

#ifdef USE_MICRO_STANDALONE_RUNTIME

// Use system(..), `gcc -shared -fPIC`, thus restrict the test to OS X for now.
#if defined(__APPLE__) && defined(__MACH__)

#include <gtest/gtest.h>
#include <spawn.h>
#include <sys/wait.h>
#include <tvm/driver/driver_api.h>
#include <tvm/relay/analysis.h>
#include <tvm/relay/expr.h>
#include <tvm/relay/transform.h>
#include <tvm/relay/type.h>
#include <tvm/runtime/micro/standalone/utvm_runtime.h>
#include <tvm/runtime/module.h>
#include <tvm/runtime/packed_func.h>
#include <tvm/runtime/registry.h>
#include <tvm/te/operation.h>
#include <tvm/topi/generic/injective.h>

TVM_REGISTER_GLOBAL("test.sch").set_body([](tvm::TVMArgs args, tvm::TVMRetValue* rv) {
  *rv = ::tvm::topi::generic::schedule_injective(args[0], args[1]);
});

TEST(MicroStandaloneRuntime, BuildModule) {
  using namespace tvm;
  auto tensor_type = relay::TensorType({2, 3}, ::tvm::runtime::DataType::Float(32));
  auto a = relay::Var("a", tensor_type);
  auto b = relay::Var("b", tensor_type);
  auto add_op = relay::Op::Get("add");
  auto x = relay::Call(add_op, {a, b}, tvm::Attrs(), {});
  auto c = relay::Var("c", tensor_type);
  auto y = relay::Call(add_op, {x, c}, tvm::Attrs(), {});
  auto func = relay::Function(relay::FreeVars(y), y, relay::Type(), {});
  auto A = tvm::runtime::NDArray::Empty({2, 3}, {kDLFloat, 32, 1}, {kDLCPU, 0});
  auto B = tvm::runtime::NDArray::Empty({2, 3}, {kDLFloat, 32, 1}, {kDLCPU, 0});
  auto C = tvm::runtime::NDArray::Empty({2, 3}, {kDLFloat, 32, 1}, {kDLCPU, 0});

  auto pA = (float*)A->data;
  auto pB = (float*)B->data;
  auto pC = (float*)C->data;

  for (int i = 0; i < 6; ++i) {
    pA[i] = i;
    pB[i] = i + 1;
    pC[i] = i + 2;
  }
  // get schedule
  auto reg = tvm::runtime::Registry::Get("relay.op._Register");
  auto s_i = tvm::runtime::Registry::Get("test.sch");
  if (!reg) {
    LOG(FATAL) << "no _Register";
  }
  if (!s_i) {
    LOG(FATAL) << "no test_sch";
  }
  (*reg)("add", "FTVMSchedule", *s_i, 10);
  // build
  auto pfb = tvm::runtime::Registry::Get("relay.build_module._BuildModule");
  tvm::runtime::Module build_mod = (*pfb)();
  auto build_f = build_mod.GetFunction("build", false);
  auto json_f = build_mod.GetFunction("get_graph_json", false);
  auto mod_f = build_mod.GetFunction("get_module", false);
  Map<tvm::Integer, tvm::Target> targets;

  Target llvm_tgt = Target("llvm");
  targets.Set(0, llvm_tgt);
  build_f(func, targets, llvm_tgt);
  std::string json = json_f();
  tvm::runtime::Module mod = mod_f();
  std::string o_fname = std::tmpnam(nullptr);
  std::string so_fname = std::tmpnam(nullptr);
  mod->SaveToFile(o_fname, "o");
  const std::vector<std::string> args = {"gcc", "-shared", "-fPIC", "-o", so_fname, o_fname};
  std::stringstream s;
  for (auto& c : args) {
    s << c << " ";
  }
  const auto ss = s.str();
  const auto ret = system(ss.c_str());
  ASSERT_EQ(ret, 0);
  // Now, execute the minimal runtime.
  auto* dsoModule = UTVMRuntimeDSOModuleCreate(so_fname.c_str(), so_fname.size());
  ASSERT_NE(dsoModule, nullptr);
  auto* handle = UTVMRuntimeCreate(json.c_str(), json.size(), dsoModule);
  ASSERT_NE(handle, nullptr);

  UTVMRuntimeSetInput(handle, 0, &A.ToDLPack()->dl_tensor);
  UTVMRuntimeSetInput(handle, 1, &B.ToDLPack()->dl_tensor);
  UTVMRuntimeSetInput(handle, 2, &C.ToDLPack()->dl_tensor);
  UTVMRuntimeRun(handle);
  auto Y = tvm::runtime::NDArray::Empty({2, 3}, {kDLFloat, 32, 1}, {kDLCPU, 0});
  UTVMRuntimeGetOutput(handle, 0, &Y.ToDLPack()->dl_tensor);
  auto* pY = (float*)Y->data;
  for (int i = 0; i < 6; ++i) {
    CHECK_LT(fabs(pY[i] - (i + (i + 1) + (i + 2))), 1e-4);
  }
  UTVMRuntimeDestroy(handle);
  UTVMRuntimeDSOModuleDestroy(dsoModule);
}

#endif
#endif

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  testing::FLAGS_gtest_death_test_style = "threadsafe";
  return RUN_ALL_TESTS();
}
