// 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 "src/input_sample/input_sample.h"

#include <fidl/fuchsia.component.decl/cpp/wire.h>
#include <fidl/fuchsia.driver.compat/cpp/wire.h>
#include <lib/async/cpp/task.h>
#include <lib/driver2/record_cpp.h>

#include <unistd.h>

namespace fdf {
using namespace fuchsia_driver_framework;
}  // namespace fdf

namespace input_sample {

namespace {

namespace fcd = fuchsia_component_decl;
namespace fio = fuchsia_io;

zx::status<fidl::ClientEnd<fuchsia_driver_compat::Device>> ConnectToParentDevice(
    const driver::Namespace* ns, std::string_view name) {
  auto result = ns->OpenService<fuchsia_driver_compat::Service>(name);
  if (result.is_error()) {
    return result.take_error();
  }
  return result.value().connect_device();
}

constexpr uint8_t kMouseButtonCount = 3;

}  // namespace

void SampleInputReport::ToFidlInputReport(
    fidl::WireTableBuilder<::fuchsia_input_report::wire::InputReport>& input_report,
    fidl::AnyArena& arena) {
  std::vector<uint8_t> pressed_buttons;
  for (uint8_t i = 0; i < kMouseButtonCount; i++) {
    if (buttons & (1 << i)) {
      pressed_buttons.push_back(i + 1);
    }
  }
  fidl::VectorView<uint8_t> buttons_vec(arena, pressed_buttons.size());
  size_t idx = 0;
  for (const auto& button : pressed_buttons) {
    buttons_vec[idx++] = button;
  }

  auto mouse_input_rpt = fuchsia_input_report::wire::MouseInputReport::Builder(arena);
  mouse_input_rpt.pressed_buttons(buttons_vec);
  mouse_input_rpt.movement_x(rel_x);
  mouse_input_rpt.movement_y(rel_y);

  input_report.mouse(mouse_input_rpt.Build());
  input_report.event_time(event_time.get());
}

void InputSampleDriver::SendFakeReport() {
  // Update fake mouse report
  report_.event_time = zx::time(zx_clock_get_monotonic());
  report_.buttons++;
  report_.rel_x++;
  report_.rel_y++;

  // Send fake mouse report
  input_report_readers_.SendReportToAllReaders(report_);

  // Run again in 1 second
  async::PostDelayedTask(
      dispatcher_,
      [this]() mutable {
        SendFakeReport();
      },
      zx::sec(1));
}

// static
zx::status<std::unique_ptr<InputSampleDriver>> InputSampleDriver::Start(
    fdf::wire::DriverStartArgs& start_args, fdf::UnownedDispatcher dispatcher,
    fidl::WireSharedClient<fdf::Node> node, driver::Namespace ns, driver::Logger logger) {
  auto driver = std::make_unique<InputSampleDriver>(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<> InputSampleDriver::Run(fidl::ServerEnd<fio::Directory> outgoing_dir) {
  // Connect to DevfsExporter.
  auto exporter = ns_.Connect<fuchsia_device_fs::Exporter>();
  if (exporter.status_value() != ZX_OK) {
    return exporter.take_error();
  }
  exporter_ = fidl::WireClient(std::move(*exporter), dispatcher_);

  // Connect to parent.
  auto parent = ConnectToParentDevice(&ns_, "default");
  if (parent.status_value() != ZX_OK) {
    FDF_SLOG(ERROR, "Failed to connect to parent", KV("status", parent.status_string()));
    return parent.take_error();
  }

  auto result = fidl::WireCall(*parent)->GetTopologicalPath();
  if (!result.ok()) {
    return zx::error(result.status());
  }

  std::string path(result->path.data(), result->path.size());

  // TODO (fxbug.dev/103199): migrate off this when fuchsia.input.report InputDevice is discoverable
  auto status = outgoing_.AddProtocol<fuchsia_input_report::InputDevice>(this, Name());
  if (status.status_value() != ZX_OK) {
    return status;
  }

  path.append("/");
  path.append(Name());

  FDF_LOG(INFO, "Exporting device to: %s", path.data());

  // Serve a connection to outgoing.
  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
  if (endpoints.is_error()) {
    return endpoints.take_error();
  }
  {
    auto status = outgoing_.Serve(std::move(endpoints->server));
    if (status.is_error()) {
      return status.take_error();
    }
  }

  // Export our protocol.
  exporter_
      ->Export(std::move(endpoints->client),
               // TODO (fxbug.dev/103199): migrate off this when fuchsia.input.report
               //                          InputDevice is discoverable
               fidl::StringView::FromExternal(std::string("svc/").append(Name())),
               fidl::StringView::FromExternal(path),
               /* INPUT_REPORT */ 26)  // TODO (fxbug.dev/98831): Non-hardcoded proto_id
      .Then([this](fidl::WireUnownedResult<fuchsia_device_fs::Exporter::Export>& result) {
        if (!result.ok()) {
          FDF_LOG(ERROR, "Exporting failed with: %s", result.status_string());
        }
      });

  status = outgoing_.Serve(std::move(outgoing_dir));
  if (status.is_error()) {
    FDF_LOG(ERROR, "Could not serve: %d", status.error_value());
    return status;
  }

  // Start sending fake reports
  SendFakeReport();

  return zx::ok();
}

void InputSampleDriver::GetInputReportsReader(GetInputReportsReaderRequestView request,
                                              GetInputReportsReaderCompleter::Sync& completer) {
  zx_status_t status = input_report_readers_.CreateReader(dispatcher_, std::move(request->reader));
  if (status != ZX_OK) {
    FDF_LOG(ERROR, "Could not create input report reader: %d", status);
  }
}

void InputSampleDriver::GetDescriptor(GetDescriptorRequestView request,
                                      GetDescriptorCompleter::Sync& completer) {
  fidl::Arena allocator;
  auto descriptor = fuchsia_input_report::wire::DeviceDescriptor::Builder(allocator);

  fuchsia_input_report::wire::DeviceInfo device_info;
  // We pick random VID/PIDs here, but these should be taken from the HID device,
  // or defined in fuchsia.input.report/device_ids.fidl
  device_info.vendor_id = 0x12345678;
  device_info.product_id = 0x87654321;

  fidl::VectorView<uint8_t> buttons(allocator, kMouseButtonCount);
  buttons[0] = 0x01;
  buttons[1] = 0x02;
  buttons[2] = 0x03;

  constexpr fuchsia_input_report::wire::Axis movement_x{
      .range = {.min = -127, .max = 127},
      .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0},
  };
  constexpr fuchsia_input_report::wire::Axis movement_y{
      .range = {.min = -127, .max = 127},
      .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0},
  };

  auto mouse_in_desc = fuchsia_input_report::wire::MouseInputDescriptor::Builder(allocator);
  mouse_in_desc.buttons(buttons);
  mouse_in_desc.movement_x(movement_x);
  mouse_in_desc.movement_y(movement_y);

  auto mouse_descriptor = fuchsia_input_report::wire::MouseDescriptor::Builder(allocator);
  mouse_descriptor.input(mouse_in_desc.Build());
  descriptor.mouse(mouse_descriptor.Build());
  descriptor.device_info(device_info);

  completer.Reply(descriptor.Build());
}

}  // namespace input_sample

FUCHSIA_DRIVER_RECORD_CPP_V1(input_sample::InputSampleDriver);
