// Copyright 2022 The Fuchsia 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 "da7219.h"

#include <fidl/fuchsia.hardware.audio/cpp/wire.h>
#include <fidl/fuchsia.hardware.i2c/cpp/wire.h>
#include <lib/driver2/service_client.h>

namespace {

// FIDL server implementation for the `fuchsia.examples.audio/Codec` protocol
class Da7219Server : public fidl::WireServer<fuchsia_hardware_audio::Codec> {
 public:
  Da7219Server(driver::Logger& logger, std::weak_ptr<I2cChannel> i2c_channel)
      : logger_(logger), i2c_channel_(i2c_channel) {}

  // Handle incoming connection requests from FIDL clients
  static fidl::ServerBindingRef<fuchsia_hardware_audio::Codec> BindDeviceClient(
      async_dispatcher_t* dispatcher, driver::Logger& logger, std::weak_ptr<I2cChannel> i2c_channel,
      fidl::ServerEnd<fuchsia_hardware_audio::Codec> request) {
    // Bind each connection request to a unique FIDL server instance
    auto server_impl = std::make_unique<Da7219Server>(logger, i2c_channel);
    return fidl::BindServer(dispatcher, std::move(request), std::move(server_impl),
                            std::mem_fn(&Da7219Server::OnUnbound));
  }

  // This method is called when a server connection is torn down.
  void OnUnbound(fidl::UnbindInfo info, fidl::ServerEnd<fuchsia_hardware_audio::Codec> server_end) {
    if (info.is_peer_closed()) {
      FDF_LOG(DEBUG, "Client disconnected");
    } else if (!info.is_user_initiated()) {
      FDF_LOG(ERROR, "Client connection unbound: %s", info.status_string());
    }
  }

  // LLCPP implementation for the Codec API.
  void Reset(ResetCompleter::Sync& completer) override {}
  void Stop(StopCompleter::Sync& completer) override {}
  void Start(StartCompleter::Sync& completer) override {}
  void GetInfo(GetInfoCompleter::Sync& completer) override {}
  void GetHealthState(GetHealthStateCompleter::Sync& completer) override {}
  void IsBridgeable(IsBridgeableCompleter::Sync& completer) override {}
  void SetBridgedMode(SetBridgedModeRequestView request,
                      SetBridgedModeCompleter::Sync& completer) override {}
  void GetDaiFormats(GetDaiFormatsCompleter::Sync& completer) override {}
  void SetDaiFormat(SetDaiFormatRequestView request,
                    SetDaiFormatCompleter::Sync& completer) override {}
  void GetPlugDetectCapabilities(GetPlugDetectCapabilitiesCompleter::Sync& completer) override {}
  void WatchPlugState(WatchPlugStateCompleter::Sync& completer) override {}
  void SignalProcessingConnect(SignalProcessingConnectRequestView request,
                               SignalProcessingConnectCompleter::Sync& completer) override {}

 private:
  driver::Logger& logger_;
  std::weak_ptr<I2cChannel> i2c_channel_;
};

}  // namespace

namespace audio {

zx::result<> Da7219Driver::Start() {
  auto channel_result = SetupI2cChannel();
  if (channel_result.is_error()) {
    return channel_result.take_error();
  }

  // Serve the fuchsia.hardware.audio/Codec protocol to clients through the
  // fuchsia.hardware.audio/CodecService wrapper.
  driver::ServiceInstanceHandler handler;
  fuchsia_hardware_audio::CodecService::Handler service(&handler);

  auto result =
      service.add_codec([this](fidl::ServerEnd<fuchsia_hardware_audio::Codec> request) -> void {
        Da7219Server::BindDeviceClient(dispatcher(), logger_, i2c_channel_, std::move(request));
      });
  ZX_ASSERT(result.is_ok());

  result =
      context().outgoing()->AddService<fuchsia_hardware_audio::CodecService>(std::move(handler));
  if (result.is_error()) {
    FDF_SLOG(ERROR, "Failed to add service", KV("status", result.status_string()));
    return result.take_error();
  }

  // Test write and read by sending arbitrary values.
  constexpr uint8_t kTestArbitraryAddress0 = 34;
  constexpr uint8_t kTestArbitraryDataToWrite0 = 56;
  constexpr uint8_t kTestArbitraryAddress1 = 78;
  auto write_status = i2c_channel_->Write(kTestArbitraryAddress0, kTestArbitraryDataToWrite0);
  if (write_status.is_error()) {
    FDF_SLOG(ERROR, "Failed to write to I2C", KV("status", write_status.status_string()));
    return write_status.take_error();
  }
  auto i2c_read = i2c_channel_->Read(kTestArbitraryAddress1);
  if (i2c_read.is_error()) {
    FDF_SLOG(ERROR, "Failed to read from I2C", KV("status", i2c_read.status_string()));
    return i2c_read.take_error();
  }
  FDF_SLOG(INFO, "Read", KV("byte", static_cast<int>(i2c_read.value())));

  FDF_SLOG(INFO, "Started");

  return zx::ok();
}

// Connect to the `fuchsia.hardware.i2c/Device` protocol offered by the parent device node.
zx::result<> Da7219Driver::SetupI2cChannel() {
  auto client_endpoint =
      driver::Connect<fuchsia_hardware_i2c::Service::Device>(*context().incoming(), "default");
  if (client_endpoint.status_value() != ZX_OK) {
    FDF_SLOG(ERROR, "Failed to setup I2cChannel", KV("status", client_endpoint.status_string()));
    return client_endpoint.take_error();
  }

  auto i2c_client = fidl::WireClient(std::move(*client_endpoint), dispatcher());
  i2c_channel_ = std::make_shared<I2cChannel>(std::move(i2c_client));
  return zx::ok();
}

}  // namespace audio

FUCHSIA_DRIVER_RECORD_CPP_V2(driver::Record<audio::Da7219Driver>);
