// 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"

namespace {

// FIDL server implementation for the `fuchsia.examples.audio/Device` protocol
class Da7219Server : public fidl::WireServer<fuchsia_hardware_audio::Codec> {
 public:
  explicit Da7219Server(driver::Namespace& ns, async_dispatcher_t* dispatcher,
                        std::weak_ptr<I2cChannel> i2c_channel)
      : i2c_channel_(i2c_channel) {
    auto logger_result = driver::Logger::Create(ns, dispatcher, "da7219-server");
    ZX_ASSERT(logger_result.is_ok());
    logger_ = std::move(*logger_result);
  }

  // Handle incoming connection requests from FIDL clients
  static fidl::ServerBindingRef<fuchsia_hardware_audio::Codec> BindDeviceClient(
      driver::Namespace& ns, async_dispatcher_t* dispatcher, 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>(ns, dispatcher, 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 {

// static
zx::status<std::unique_ptr<Da7219Driver>> Da7219Driver::Start(
    fuchsia_driver_framework::wire::DriverStartArgs& start_args, fdf::UnownedDispatcher dispatcher,
    fidl::WireSharedClient<fuchsia_driver_framework::Node> node, driver::Namespace ns,
    driver::Logger logger) {
  auto driver = std::make_unique<Da7219Driver>(dispatcher->async_dispatcher(), std::move(node),
                                               std::move(ns), std::move(logger));
  auto result = driver->Run(std::move(start_args.outgoing_dir()));
  if (result.is_error()) {
    return result.take_error();
  }

  return zx::ok(std::move(driver));
}

zx::status<> Da7219Driver::Run(fidl::ServerEnd<fuchsia_io::Directory> outgoing_dir) {
  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.
  component::ServiceHandler handler;
  fuchsia_hardware_audio::CodecService::Handler service(&handler);

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

  result = 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();
  }

  auto status = outgoing_.Serve(std::move(outgoing_dir));
  if (status.is_error()) {
    FDF_SLOG(ERROR, "Failed to serve outgoing directory", KV("status", status.status_string()));
    return status.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::status<> Da7219Driver::SetupI2cChannel() {
  auto client_endpoint = ns_.Connect<fuchsia_hardware_i2c::Device>();
  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_V1(audio::Da7219Driver);
