// Copyright 2022 The Pigweed 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
//
//     https://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 "pw_rpc/pwpb/internal/method_union.h"

#include <array>

#include "gtest/gtest.h"
#include "pw_rpc/internal/test_utils.h"
#include "pw_rpc/service.h"
#include "pw_rpc_pwpb_private/internal_test_utils.h"
#include "pw_rpc_test_protos/test.pwpb.h"

namespace pw::rpc::internal {
namespace {

template <typename Implementation>
class FakeGeneratedService : public Service {
 public:
  constexpr FakeGeneratedService(uint32_t id) : Service(id, kMethods) {}

  static constexpr std::array<PwpbMethodUnion, 4> kMethods = {
      GetPwpbOrRawMethodFor<&Implementation::DoNothing,
                            MethodType::kUnary,
                            pw::rpc::test::Empty::Message,
                            pw::rpc::test::Empty::Message>(
          10u,
          kPwpbMethodSerde<&pw::rpc::test::Empty::kMessageFields,
                           &pw::rpc::test::Empty::kMessageFields>),
      GetPwpbOrRawMethodFor<&Implementation::RawStream,
                            MethodType::kServerStreaming,
                            pw::rpc::test::TestRequest::Message,
                            pw::rpc::test::TestResponse::Message>(
          11u,
          kPwpbMethodSerde<&pw::rpc::test::TestRequest::kMessageFields,
                           &pw::rpc::test::TestResponse::kMessageFields>),
      GetPwpbOrRawMethodFor<&Implementation::AddFive,
                            MethodType::kUnary,
                            pw::rpc::test::TestRequest::Message,
                            pw::rpc::test::TestResponse::Message>(
          12u,
          kPwpbMethodSerde<&pw::rpc::test::TestRequest::kMessageFields,
                           &pw::rpc::test::TestResponse::kMessageFields>),
      GetPwpbOrRawMethodFor<&Implementation::StartStream,
                            MethodType::kServerStreaming,
                            pw::rpc::test::TestRequest::Message,
                            pw::rpc::test::TestResponse::Message>(
          13u,
          kPwpbMethodSerde<&pw::rpc::test::TestRequest::kMessageFields,
                           &pw::rpc::test::TestResponse::kMessageFields>),
  };
};

class FakeGeneratedServiceImpl
    : public FakeGeneratedService<FakeGeneratedServiceImpl> {
 public:
  FakeGeneratedServiceImpl(uint32_t id) : FakeGeneratedService(id) {}

  Status AddFive(const pw::rpc::test::TestRequest::Message& request,
                 pw::rpc::test::TestResponse::Message& response) {
    last_request = request;
    response.value = request.integer + 5;
    return Status::Unauthenticated();
  }

  void DoNothing(ConstByteSpan, RawUnaryResponder& responder) {
    ASSERT_EQ(OkStatus(), responder.Finish({}, Status::Unknown()));
  }

  void RawStream(ConstByteSpan, RawServerWriter& writer) {
    last_raw_writer = std::move(writer);
  }

  void StartStream(
      const pw::rpc::test::TestRequest::Message& request,
      PwpbServerWriter<pw::rpc::test::TestResponse::Message>& writer) {
    last_request = request;
    last_writer = std::move(writer);
  }

  pw::rpc::test::TestRequest::Message last_request;
  PwpbServerWriter<pw::rpc::test::TestResponse::Message> last_writer;
  RawServerWriter last_raw_writer;
};

TEST(PwpbMethodUnion, Raw_CallsUnaryMethod) {
  const Method& method =
      std::get<0>(FakeGeneratedServiceImpl::kMethods).method();
  ServerContextForTest<FakeGeneratedServiceImpl> context(method);
  rpc_lock().lock();
  method.Invoke(context.get(), context.request({}));

  const Packet& response = context.output().last_packet();
  EXPECT_EQ(response.status(), Status::Unknown());
}

TEST(PwpbMethodUnion, Raw_CallsServerStreamingMethod) {
  PW_ENCODE_PB(
      pw::rpc::test::TestRequest, request, .integer = 555, .status_code = 0);

  const Method& method =
      std::get<1>(FakeGeneratedServiceImpl::kMethods).method();
  ServerContextForTest<FakeGeneratedServiceImpl> context(method);

  rpc_lock().lock();
  method.Invoke(context.get(), context.request(request));

  EXPECT_TRUE(context.service().last_raw_writer.active());
  EXPECT_EQ(OkStatus(), context.service().last_raw_writer.Finish());
  EXPECT_EQ(context.output().last_packet().type(), PacketType::RESPONSE);
}

TEST(PwpbMethodUnion, Pwpb_CallsUnaryMethod) {
  PW_ENCODE_PB(
      pw::rpc::test::TestRequest, request, .integer = 123, .status_code = 3);

  const Method& method =
      std::get<2>(FakeGeneratedServiceImpl::kMethods).method();
  ServerContextForTest<FakeGeneratedServiceImpl> context(method);
  rpc_lock().lock();
  method.Invoke(context.get(), context.request(request));

  const Packet& response = context.output().last_packet();
  EXPECT_EQ(response.status(), Status::Unauthenticated());

  // Field 1 (encoded as 1 << 3) with 128 as the value.
  constexpr std::byte expected[]{
      std::byte{0x08}, std::byte{0x80}, std::byte{0x01}};

  EXPECT_EQ(sizeof(expected), response.payload().size());
  EXPECT_EQ(0,
            std::memcmp(expected, response.payload().data(), sizeof(expected)));

  EXPECT_EQ(123, context.service().last_request.integer);
  EXPECT_EQ(3u, context.service().last_request.status_code);
}

TEST(PwpbMethodUnion, Pwpb_CallsServerStreamingMethod) {
  PW_ENCODE_PB(
      pw::rpc::test::TestRequest, request, .integer = 555, .status_code = 0);

  const Method& method =
      std::get<3>(FakeGeneratedServiceImpl::kMethods).method();
  ServerContextForTest<FakeGeneratedServiceImpl> context(method);

  rpc_lock().lock();
  method.Invoke(context.get(), context.request(request));

  EXPECT_EQ(555, context.service().last_request.integer);
  EXPECT_TRUE(context.service().last_writer.active());

  EXPECT_EQ(OkStatus(), context.service().last_writer.Finish());
  EXPECT_EQ(context.output().last_packet().type(), PacketType::RESPONSE);
}

}  // namespace
}  // namespace pw::rpc::internal
