// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/devtools/protocol/smart_card_emulation_handler.h"

#include <optional>
#include <string_view>

#include "base/containers/fixed_flat_map.h"
#include "base/types/expected_macros.h"
#include "base/uuid.h"
#include "content/browser/devtools/protocol/smart_card_emulation.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/smart_card/emulation/emulated_smart_card_connection.h"
#include "content/browser/smart_card/emulation/emulated_smart_card_context.h"
#include "content/browser/smart_card/emulation/emulated_smart_card_transaction.h"
#include "content/browser/smart_card/smart_card_service.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/smart_card_delegate.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
#include "services/device/public/mojom/smart_card.mojom.h"

namespace content::protocol {

namespace {
std::string GenerateRequestId() {
  return base::Uuid::GenerateRandomV4().AsLowercaseString();
}

// Convert binary data (std::vector<uint8_t>) to Protocol Binary.
protocol::Binary ToProtocolBinary(const std::vector<uint8_t>& data) {
  return protocol::Binary::fromSpan(std::move(data));
}

// Convert Protocol Binary to binary data (std::vector<uint8_t>).
std::vector<uint8_t> ToVector(const protocol::Binary& binary) {
  return std::vector<uint8_t>(binary.begin(), binary.end());
}

// Convert the Protocol error string to the Mojo error enum.
device::mojom::SmartCardError ToMojoSmartCardError(
    const std::string& result_code) {
  namespace ResultCodeEnum = protocol::SmartCardEmulation::ResultCodeEnum;

  static constexpr auto kErrorMap = base::MakeFixedFlatMap<
      std::string_view, device::mojom::SmartCardError>({
      {ResultCodeEnum::Cancelled, device::mojom::SmartCardError::kCancelled},
      {ResultCodeEnum::CommError, device::mojom::SmartCardError::kCommError},
      {ResultCodeEnum::InsufficientBuffer,
       device::mojom::SmartCardError::kInsufficientBuffer},
      {ResultCodeEnum::InternalError,
       device::mojom::SmartCardError::kInternalError},
      {ResultCodeEnum::InvalidHandle,
       device::mojom::SmartCardError::kInvalidHandle},
      {ResultCodeEnum::InvalidParameter,
       device::mojom::SmartCardError::kInvalidParameter},
      {ResultCodeEnum::InvalidValue,
       device::mojom::SmartCardError::kInvalidValue},
      {ResultCodeEnum::NoMemory, device::mojom::SmartCardError::kNoMemory},
      {ResultCodeEnum::NoReadersAvailable,
       device::mojom::SmartCardError::kNoReadersAvailable},
      {ResultCodeEnum::NoService, device::mojom::SmartCardError::kNoService},
      {ResultCodeEnum::NoSmartcard,
       device::mojom::SmartCardError::kNoSmartcard},
      {ResultCodeEnum::NotReady, device::mojom::SmartCardError::kNotReady},
      {ResultCodeEnum::NotTransacted,
       device::mojom::SmartCardError::kNotTransacted},
      {ResultCodeEnum::ProtoMismatch,
       device::mojom::SmartCardError::kProtoMismatch},
      {ResultCodeEnum::ReaderUnavailable,
       device::mojom::SmartCardError::kReaderUnavailable},
      {ResultCodeEnum::RemovedCard,
       device::mojom::SmartCardError::kRemovedCard},
      {ResultCodeEnum::ResetCard, device::mojom::SmartCardError::kResetCard},
      {ResultCodeEnum::ServerTooBusy,
       device::mojom::SmartCardError::kServerTooBusy},
      {ResultCodeEnum::ServiceStopped,
       device::mojom::SmartCardError::kServiceStopped},
      {ResultCodeEnum::SharingViolation,
       device::mojom::SmartCardError::kSharingViolation},
      {ResultCodeEnum::Shutdown, device::mojom::SmartCardError::kShutdown},
      {ResultCodeEnum::SystemCancelled,
       device::mojom::SmartCardError::kSystemCancelled},
      {ResultCodeEnum::Timeout, device::mojom::SmartCardError::kTimeout},
      {ResultCodeEnum::Unexpected, device::mojom::SmartCardError::kUnexpected},
      {ResultCodeEnum::Unknown, device::mojom::SmartCardError::kUnknown},
      {ResultCodeEnum::UnknownCard,
       device::mojom::SmartCardError::kUnknownCard},
      {ResultCodeEnum::UnknownReader,
       device::mojom::SmartCardError::kUnknownReader},
      {ResultCodeEnum::UnpoweredCard,
       device::mojom::SmartCardError::kUnpoweredCard},
      {ResultCodeEnum::UnresponsiveCard,
       device::mojom::SmartCardError::kUnresponsiveCard},
      {ResultCodeEnum::UnsupportedCard,
       device::mojom::SmartCardError::kUnsupportedCard},
      {ResultCodeEnum::UnsupportedFeature,
       device::mojom::SmartCardError::kUnsupportedFeature},
  });

  auto it = kErrorMap.find(result_code);
  if (it != kErrorMap.end()) {
    return it->second;
  }

  // The DevTools dispatcher guarantees that 'result_code' matches one of the
  // string literals defined in the PDL (ResultCodeEnum), so this branch
  // is unreachable unless the PDL and this map are out of sync.
  NOTREACHED();
}

// Convert Mojo Disposition enum to Protocol String.
String ToProtocolDisposition(device::mojom::SmartCardDisposition disposition) {
  switch (disposition) {
    case device::mojom::SmartCardDisposition::kLeave:
      return SmartCardEmulation::DispositionEnum::LeaveCard;
    case device::mojom::SmartCardDisposition::kReset:
      return SmartCardEmulation::DispositionEnum::ResetCard;
    case device::mojom::SmartCardDisposition::kUnpower:
      return SmartCardEmulation::DispositionEnum::UnpowerCard;
    case device::mojom::SmartCardDisposition::kEject:
      return SmartCardEmulation::DispositionEnum::EjectCard;
  }
  // The 'default' case is intentionally omitted to ensure a compile-time error
  // if a new value is added to the SmartCardDisposition enum.
  NOTREACHED();
}

// Convert Mojo SmartCardReaderStateFlags to Protocol reader state flags.
std::unique_ptr<SmartCardEmulation::ReaderStateFlags>
ToProtocolReaderStateFlags(
    const device::mojom::SmartCardReaderStateFlags& flags) {
  return SmartCardEmulation::ReaderStateFlags::Create()
      .SetUnaware(flags.unaware)
      .SetIgnore(flags.ignore)
      .SetChanged(flags.changed)
      .SetUnknown(flags.unknown)
      .SetUnavailable(flags.unavailable)
      .SetEmpty(flags.empty)
      .SetPresent(flags.present)
      .SetExclusive(flags.exclusive)
      .SetInuse(flags.inuse)
      .SetMute(flags.mute)
      .SetUnpowered(flags.unpowered)
      .Build();
}

// Convert Pdl Reader State Flags to mojo.
device::mojom::SmartCardReaderStateFlagsPtr ToMojoReaderStateFlags(
    protocol::SmartCardEmulation::ReaderStateFlags* flags) {
  auto mojo_flags = device::mojom::SmartCardReaderStateFlags::New();

  if (!flags) {
    return mojo_flags;
  }

  mojo_flags->unaware = flags->GetUnaware(false);
  mojo_flags->ignore = flags->GetIgnore(false);
  mojo_flags->changed = flags->GetChanged(false);
  mojo_flags->unknown = flags->GetUnknown(false);
  mojo_flags->unavailable = flags->GetUnavailable(false);
  mojo_flags->empty = flags->GetEmpty(false);
  mojo_flags->present = flags->GetPresent(false);
  mojo_flags->exclusive = flags->GetExclusive(false);
  mojo_flags->inuse = flags->GetInuse(false);
  mojo_flags->mute = flags->GetMute(false);
  mojo_flags->unpowered = flags->GetUnpowered(false);

  return mojo_flags;
}

// Convert Mojo ReaderStates to Protocol Array.
std::unique_ptr<protocol::Array<protocol::SmartCardEmulation::ReaderStateIn>>
ToProtocolReaderStates(
    const std::vector<device::mojom::SmartCardReaderStateInPtr>&
        reader_states) {
  auto protocol_states = std::make_unique<
      protocol::Array<protocol::SmartCardEmulation::ReaderStateIn>>();

  for (const auto& rs : reader_states) {
    auto in =
        SmartCardEmulation::ReaderStateIn::Create()
            .SetReader(rs->reader)
            .SetCurrentInsertionCount(rs->current_count)
            .SetCurrentState(ToProtocolReaderStateFlags(*rs->current_state))
            .Build();
    protocol_states->push_back(std::move(in));
  }
  return protocol_states;
}

// Convert Protocol ReaderStateOut to Mojo SmartCardReaderStateOut.
device::mojom::SmartCardReaderStateOutPtr ToMojoReaderStateOut(
    protocol::SmartCardEmulation::ReaderStateOut& proto_state) {
  auto mojo_state = device::mojom::SmartCardReaderStateOut::New();

  mojo_state->reader = proto_state.GetReader();
  mojo_state->event_count = proto_state.GetEventCount();
  mojo_state->answer_to_reset = ToVector(proto_state.GetAtr());
  mojo_state->event_state = ToMojoReaderStateFlags(proto_state.GetEventState());
  return mojo_state;
}

// Convert Mojo Enum to Protocol String.
std::string ToProtocolShareMode(device::mojom::SmartCardShareMode share_mode) {
  switch (share_mode) {
    case device::mojom::SmartCardShareMode::kShared:
      return SmartCardEmulation::ShareModeEnum::Shared;
    case device::mojom::SmartCardShareMode::kExclusive:
      return SmartCardEmulation::ShareModeEnum::Exclusive;
    case device::mojom::SmartCardShareMode::kDirect:
      return SmartCardEmulation::ShareModeEnum::Direct;
  }
  // The 'default' case is intentionally omitted to ensure a compile-time error
  // if a new value is added to the SmartCardShareMode enum.
  NOTREACHED();
}

// Convert Mojo Struct to ProtocolSet Object.
std::unique_ptr<protocol::SmartCardEmulation::ProtocolSet>
ToProtocolProtocolSet(const device::mojom::SmartCardProtocolsPtr& protocols) {
  auto builder = protocol::SmartCardEmulation::ProtocolSet::Create();
  if (protocols) {
    builder.SetT0(protocols->t0);
    builder.SetT1(protocols->t1);
    builder.SetRaw(protocols->raw);
  } else {
    builder.SetT0(false);
    builder.SetT1(false);
    builder.SetRaw(false);
  }
  return builder.Build();
}

// Convert Mojo Protocol to Protocol SmartCardProtocol.
std::optional<std::string> ToProtocolSmartCardProtocol(
    device::mojom::SmartCardProtocol protocol) {
  switch (protocol) {
    case device::mojom::SmartCardProtocol::kT0:
      return protocol::SmartCardEmulation::ProtocolEnum::T0;
    case device::mojom::SmartCardProtocol::kT1:
      return protocol::SmartCardEmulation::ProtocolEnum::T1;
    case device::mojom::SmartCardProtocol::kRaw:
      return protocol::SmartCardEmulation::ProtocolEnum::Raw;
    case device::mojom::SmartCardProtocol::kUndefined:
      return std::nullopt;
  }
  // The 'default' case is intentionally omitted to ensure a compile-time error
  // if a new value is added to the mojo SmartCardProtocol enum.
  NOTREACHED();
}

device::mojom::SmartCardProtocol ToMojoSmartCardProtocol(
    const std::optional<std::string>& protocol_str) {
  if (!protocol_str.has_value() || protocol_str->empty()) {
    return device::mojom::SmartCardProtocol::kUndefined;
  }

  namespace Protocol = protocol::SmartCardEmulation::ProtocolEnum;
  using MojomProtocol = device::mojom::SmartCardProtocol;

  static constexpr auto kProtocolMap =
      base::MakeFixedFlatMap<std::string_view, MojomProtocol>({
          {Protocol::Raw, MojomProtocol::kRaw},
          {Protocol::T0, MojomProtocol::kT0},
          {Protocol::T1, MojomProtocol::kT1},
      });

  auto it = kProtocolMap.find(*protocol_str);
  if (it != kProtocolMap.end()) {
    return it->second;
  }
  NOTREACHED();
}

// Convert optional Protocol array to standard vector required by Mojo.
std::vector<std::string> ToMojoStringVector(
    std::unique_ptr<protocol::Array<String>> in_readers) {
  if (!in_readers) {
    return {};
  }
  return std::move(*in_readers);
}

// Convert the Protocol reader states array to a vector of Mojo reader states.
std::vector<device::mojom::SmartCardReaderStateOutPtr> ToMojoReaderStates(
    std::unique_ptr<
        protocol::Array<protocol::SmartCardEmulation::ReaderStateOut>>
        in_states) {
  if (!in_states) {
    return {};
  }

  std::vector<device::mojom::SmartCardReaderStateOutPtr> out_states;
  out_states.reserve(in_states->size());

  for (const auto& state : *in_states) {
    out_states.push_back(ToMojoReaderStateOut(*state));
  }

  return out_states;
}

// Convert Protocol ConnectionState to Mojo SmartCardConnectionState.
device::mojom::SmartCardConnectionState ToMojoSmartCardConnectionState(
    const protocol::SmartCardEmulation::ConnectionState state) {
  namespace Protocol = protocol::SmartCardEmulation::ConnectionStateEnum;
  using MojomState = device::mojom::SmartCardConnectionState;

  static constexpr auto kStateMap =
      base::MakeFixedFlatMap<std::string_view, MojomState>({
          {Protocol::Absent, MojomState::kAbsent},
          {Protocol::Negotiable, MojomState::kNegotiable},
          {Protocol::Powered, MojomState::kPowered},
          {Protocol::Present, MojomState::kPresent},
          {Protocol::Specific, MojomState::kSpecific},
          {Protocol::Swallowed, MojomState::kSwallowed},
      });

  auto it = kStateMap.find(state);
  if (it != kStateMap.end()) {
    return it->second;
  }

  // The DevTools dispatcher guarantees that 'state' matches one of the
  // string literals defined in the PDL (ConnectionStateEnum), so this branch
  // is unreachable unless the PDL and this map are out of sync.
  NOTREACHED();
}

}  // namespace

SmartCardEmulationHandler::SmartCardEmulationHandler(
    content::WebContents* web_contents)
    : DevToolsDomainHandler(SmartCardEmulation::Metainfo::domainName),
      content::WebContentsObserver(web_contents) {}

SmartCardEmulationHandler::~SmartCardEmulationHandler() = default;

// static
std::vector<SmartCardEmulationHandler*> SmartCardEmulationHandler::ForAgentHost(
    DevToolsAgentHostImpl* host) {
  return host->HandlersByName<SmartCardEmulationHandler>(
      SmartCardEmulation::Metainfo::domainName);
}

void SmartCardEmulationHandler::Wire(UberDispatcher* dispatcher) {
  frontend_ =
      std::make_unique<SmartCardEmulation::Frontend>(dispatcher->channel());
  SmartCardEmulation::Dispatcher::wire(dispatcher, this);
}

void SmartCardEmulationHandler::SetRenderer(int process_host_id,
                                            RenderFrameHostImpl* frame_host) {
  // If frame_host changes, update the observer target.
  Observe(content::WebContents::FromRenderFrameHost(frame_host));
}

void SmartCardEmulationHandler::ReadyToCommitNavigation(
    content::NavigationHandle* handle) {
  // Automatically re-apply emulation when the frame changes.
  if (IsEnabled() && handle->IsInPrimaryMainFrame() && !handle->IsErrorPage()) {
    UpdateEmulationOverride(handle->GetRenderFrameHost());
  }
}

void SmartCardEmulationHandler::UpdateEmulationOverride(
    content::RenderFrameHost* rfh) {
  CHECK(IsEnabled());
  CHECK(rfh);

  auto* delegate =
      content::GetContentClient()->browser()->GetSmartCardDelegate();
  if (!delegate) {
    return;
  }

  auto factory_getter = base::BindRepeating(
      [](base::WeakPtr<EmulatedSmartCardContextFactory> factory) {
        mojo::PendingRemote<device::mojom::SmartCardContextFactory> remote;
        if (factory) {
          factory->BindReceiver(remote.InitWithNewPipeAndPassReceiver());
        }
        return remote;
      },
      factory_->GetWeakPtr());

  delegate->SetEmulationFactory(rfh->GetGlobalId(), std::move(factory_getter));
}

DispatchResponse SmartCardEmulationHandler::Enable() {
  if (IsEnabled()) {
    return DispatchResponse::Success();
  }

  if (!content::GetContentClient()->browser()->GetSmartCardDelegate()) {
    return DispatchResponse::ServerError(
        "Smart Card emulation is not supported on this platform.");
  }

  if (!web_contents()) {
    return DispatchResponse::ServerError("WebContents not available");
  }

  factory_ = std::make_unique<EmulatedSmartCardContextFactory>(*this);

  UpdateEmulationOverride(web_contents()->GetPrimaryMainFrame());
  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::Disable() {
  if (!IsEnabled()) {
    return DispatchResponse::Success();
  }

  if (web_contents()) {
    content::SmartCardDelegate* delegate =
        content::GetContentClient()->browser()->GetSmartCardDelegate();
    if (delegate) {
      delegate->ClearEmulationFactory(
          web_contents()->GetPrimaryMainFrame()->GetGlobalId());
    }
  }

  factory_.reset();

  return DispatchResponse::Success();
}

SmartCardEmulationHandler::PendingConnect::PendingConnect(
    device::mojom::SmartCardContext::ConnectCallback callback,
    mojo::PendingRemote<device::mojom::SmartCardConnectionWatcher> watcher)
    : PendingRequestImpl(std::move(callback)), watcher_(std::move(watcher)) {}

SmartCardEmulationHandler::PendingConnect::~PendingConnect() = default;
SmartCardEmulationHandler::PendingConnect::PendingConnect(PendingConnect&&) =
    default;

void SmartCardEmulationHandler::AddPendingRequest(const std::string& request_id,
                                                  PendingRequest request) {
  pending_requests_.emplace(request_id, std::move(request));
}

template <typename T>
base::expected<T, std::string> SmartCardEmulationHandler::TakePendingRequest(
    const std::string& request_id) {
  auto it = pending_requests_.find(request_id);
  if (it == pending_requests_.end()) {
    return base::unexpected("Request ID not found");
  }

  // Check if the variant holds the specific template instantiation T.
  T* request_ptr = std::get_if<T>(&it->second);
  if (!request_ptr) {
    return base::unexpected("Request type mismatch");
  }

  T request = std::move(*request_ptr);
  pending_requests_.erase(it);
  return request;
}

base::expected<void, std::string>
SmartCardEmulationHandler::CompleteListReaders(
    const std::string& request_id,
    std::vector<std::string> readers) {
  ASSIGN_OR_RETURN(auto req,
                   TakePendingRequest<PendingListReaders>(request_id));
  std::move(req.callback())
      .Run(device::mojom::SmartCardListReadersResult::NewReaders(
          std::move(readers)));
  return base::ok();
}

base::expected<void, std::string>
SmartCardEmulationHandler::CompleteEstablishContext(
    const std::string& request_id,
    const uint32_t context_id) {
  ASSIGN_OR_RETURN(auto req,
                   TakePendingRequest<PendingCreateContext>(request_id));

  auto context_impl = std::make_unique<EmulatedSmartCardContext>(
      weak_ptr_factory_.GetWeakPtr(), context_id);

  mojo::PendingRemote<device::mojom::SmartCardContext> remote;

  mojo::MakeSelfOwnedReceiver(std::move(context_impl),
                              remote.InitWithNewPipeAndPassReceiver());

  std::move(req.callback())
      .Run(device::mojom::SmartCardCreateContextResult::NewContext(
          std::move(remote)));
  return base::ok();
}

base::expected<void, std::string> SmartCardEmulationHandler::CompleteConnect(
    const std::string& request_id,
    const uint32_t handle,
    device::mojom::SmartCardProtocol active_protocol) {
  ASSIGN_OR_RETURN(auto req, TakePendingRequest<PendingConnect>(request_id));

  auto success_data = device::mojom::SmartCardConnectSuccess::New();
  success_data->active_protocol = active_protocol;

  mojo::PendingRemote<device::mojom::SmartCardConnectionWatcher> watcher =
      req.TakeWatcher();

  auto connection_impl = std::make_unique<EmulatedSmartCardConnection>(
      weak_ptr_factory_.GetWeakPtr(), handle, std::move(watcher));

  mojo::PendingRemote<device::mojom::SmartCardConnection> connection_remote;

  mojo::MakeSelfOwnedReceiver(
      std::move(connection_impl),
      connection_remote.InitWithNewPipeAndPassReceiver());

  success_data->connection = std::move(connection_remote);

  std::move(req.callback())
      .Run(device::mojom::SmartCardConnectResult::NewSuccess(
          std::move(success_data)));

  return base::ok();
}

base::expected<void, std::string>
SmartCardEmulationHandler::CompleteGetStatusChange(
    const std::string& request_id,
    std::vector<device::mojom::SmartCardReaderStateOutPtr> reader_states) {
  ASSIGN_OR_RETURN(auto req,
                   TakePendingRequest<PendingGetStatusChange>(request_id));
  std::move(req.callback())
      .Run(device::mojom::SmartCardStatusChangeResult::NewReaderStates(
          std::move(reader_states)));
  return base::ok();
}

base::expected<void, std::string> SmartCardEmulationHandler::CompleteStatus(
    const std::string& request_id,
    device::mojom::SmartCardStatusPtr status_data) {
  ASSIGN_OR_RETURN(auto req, TakePendingRequest<PendingStatus>(request_id));
  std::move(req.callback())
      .Run(device::mojom::SmartCardStatusResult::NewStatus(
          std::move(status_data)));
  return base::ok();
}

base::expected<void, std::string> SmartCardEmulationHandler::CompleteDataResult(
    const std::string& request_id,
    std::vector<uint8_t> response) {
  ASSIGN_OR_RETURN(auto req, TakePendingRequest<PendingDataResult>(request_id));
  std::move(req.callback())
      .Run(device::mojom::SmartCardDataResult::NewData(std::move(response)));
  return base::ok();
}

base::expected<void, std::string>
SmartCardEmulationHandler::CompleteBeginTransaction(
    const std::string& request_id,
    uint32_t handle) {
  ASSIGN_OR_RETURN(auto req,
                   TakePendingRequest<PendingBeginTransaction>(request_id));

  mojo::PendingAssociatedRemote<device::mojom::SmartCardTransaction>
      transaction_remote;

  auto transaction_impl = std::make_unique<EmulatedSmartCardTransaction>(
      weak_ptr_factory_.GetWeakPtr(), handle);

  mojo::MakeSelfOwnedAssociatedReceiver(
      std::move(transaction_impl),
      transaction_remote.InitWithNewEndpointAndPassReceiver());

  std::move(req.callback())
      .Run(device::mojom::SmartCardTransactionResult::NewTransaction(
          std::move(transaction_remote)));
  return base::ok();
}

base::expected<void, std::string>
SmartCardEmulationHandler::CompletePlainResult(const std::string& request_id) {
  ASSIGN_OR_RETURN(auto req,
                   TakePendingRequest<PendingPlainResult>(request_id));
  std::move(req.callback())
      .Run(device::mojom::SmartCardResult::NewSuccess(
          device::mojom::SmartCardSuccess::kOk));
  return base::ok();
}

base::expected<void, std::string>
SmartCardEmulationHandler::CompleteReleaseContext(
    const std::string& request_id) {
  RETURN_IF_ERROR(TakePendingRequest<PendingReleaseContext>(request_id));
  return base::ok();
}

base::expected<void, std::string> SmartCardEmulationHandler::FailRequest(
    const std::string& request_id,
    device::mojom::SmartCardError error) {
  auto it = pending_requests_.find(request_id);
  if (it == pending_requests_.end()) {
    return base::unexpected("Request ID not found");
  }

  PendingRequest request_variant = std::move(it->second);
  pending_requests_.erase(it);

  std::visit([error](auto&& request) { request.ReportError(error); },
             request_variant);

  return base::ok();
}

DispatchResponse SmartCardEmulationHandler::ReportEstablishContextResult(
    const String& in_requestId,
    const int in_contextId) {
  RETURN_IF_ERROR(CompleteEstablishContext(in_requestId, in_contextId),
                  [](const std::string& error) {
                    return DispatchResponse::ServerError(error);
                  });
  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportListReadersResult(
    const String& in_requestId,
    std::unique_ptr<protocol::Array<String>> in_readers) {
  RETURN_IF_ERROR(CompleteListReaders(
                      in_requestId, ToMojoStringVector(std::move(in_readers))),
                  [](const std::string& error) {
                    return DispatchResponse::ServerError(error);
                  });

  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportConnectResult(
    const String& in_requestId,
    const int in_handle,
    std::optional<String> in_activeProtocol) {
  RETURN_IF_ERROR(CompleteConnect(in_requestId, in_handle,
                                  ToMojoSmartCardProtocol(in_activeProtocol)),
                  [](const std::string& error) {
                    return DispatchResponse::ServerError(error);
                  });
  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportGetStatusChangeResult(
    const String& in_requestId,
    std::unique_ptr<
        protocol::Array<protocol::SmartCardEmulation::ReaderStateOut>>
        in_readerStates) {
  RETURN_IF_ERROR(
      CompleteGetStatusChange(in_requestId,
                              ToMojoReaderStates(std::move(in_readerStates))),
      [](const std::string& error) {
        return DispatchResponse::ServerError(error);
      });

  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportBeginTransactionResult(
    const String& in_requestId,
    const int in_handle) {
  RETURN_IF_ERROR(CompleteBeginTransaction(in_requestId, in_handle),
                  [](const std::string& error) {
                    return DispatchResponse::ServerError(error);
                  });

  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportDataResult(
    const String& in_requestId,
    const Binary& in_data) {
  RETURN_IF_ERROR(
      CompleteDataResult(in_requestId,
                         std::vector<uint8_t>(in_data.begin(), in_data.end())),
      [](const std::string& error) {
        return DispatchResponse::ServerError(error);
      });

  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportPlainResult(
    const String& in_requestId) {
  RETURN_IF_ERROR(CompletePlainResult(in_requestId),
                  [](const std::string& error) {
                    return DispatchResponse::ServerError(error);
                  });

  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportStatusResult(
    const String& in_requestId,
    const String& in_readerName,
    const String& in_state,
    const Binary& in_atr,
    std::optional<String> in_protocol) {
  std::vector<uint8_t> atr(in_atr.begin(), in_atr.end());

  RETURN_IF_ERROR(
      CompleteStatus(
          in_requestId,
          device::mojom::SmartCardStatus::New(
              in_readerName, ToMojoSmartCardConnectionState(in_state),
              ToMojoSmartCardProtocol(in_protocol), std::move(atr))),
      [](const std::string& error) {
        return DispatchResponse::ServerError(error);
      });

  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportReleaseContextResult(
    const String& in_requestId) {
  RETURN_IF_ERROR(CompleteReleaseContext(in_requestId),
                  [](const std::string& error) {
                    return DispatchResponse::ServerError(error);
                  });
  return DispatchResponse::Success();
}

DispatchResponse SmartCardEmulationHandler::ReportError(
    const String& in_requestId,
    const String& in_resultCode) {
  RETURN_IF_ERROR(
      FailRequest(in_requestId, ToMojoSmartCardError(in_resultCode)),
      [](const std::string& error) {
        return DispatchResponse::ServerError(error);
      });
  return DispatchResponse::Success();
}

void SmartCardEmulationHandler::OnCreateContext(
    device::mojom::SmartCardContextFactory::CreateContextCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingCreateContext(std::move(callback)));
  frontend_->EstablishContextRequested(request_id);
}

void SmartCardEmulationHandler::OnListReaders(
    uint32_t context_id,
    device::mojom::SmartCardContext::ListReadersCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingListReaders(std::move(callback)));
  frontend_->ListReadersRequested(request_id, context_id);
}

void SmartCardEmulationHandler::OnGetStatusChange(
    uint32_t context_id,
    base::TimeDelta timeout,
    std::vector<device::mojom::SmartCardReaderStateInPtr> reader_states,
    device::mojom::SmartCardContext::GetStatusChangeCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingGetStatusChange(std::move(callback)));
  frontend_->GetStatusChangeRequested(request_id, context_id,
                                      ToProtocolReaderStates(reader_states),
                                      timeout.InMilliseconds());
}

void SmartCardEmulationHandler::OnCancel(
    uint32_t context_id,
    device::mojom::SmartCardContext::CancelCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingPlainResult(std::move(callback)));
  frontend_->CancelRequested(request_id, context_id);
}

void SmartCardEmulationHandler::OnConnect(
    uint32_t context_id,
    const std::string& reader,
    device::mojom::SmartCardShareMode share_mode,
    device::mojom::SmartCardProtocolsPtr preferred_protocols,
    mojo::PendingRemote<device::mojom::SmartCardConnectionWatcher> watcher,
    device::mojom::SmartCardContext::ConnectCallback callback) {
  std::string request_id = GenerateRequestId();

  AddPendingRequest(request_id,
                    PendingConnect(std::move(callback), std::move(watcher)));

  frontend_->ConnectRequested(
      request_id, context_id, reader, ToProtocolShareMode(share_mode),
      ToProtocolProtocolSet(std::move(preferred_protocols)));
}

void SmartCardEmulationHandler::OnDisconnect(
    uint32_t handle,
    device::mojom::SmartCardDisposition disposition,
    device::mojom::SmartCardConnection::DisconnectCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingPlainResult(std::move(callback)));
  frontend_->DisconnectRequested(request_id, handle,
                                 ToProtocolDisposition(disposition));
}

void SmartCardEmulationHandler::OnControl(
    uint32_t handle,
    uint32_t control_code,
    const std::vector<uint8_t>& data,
    device::mojom::SmartCardConnection::ControlCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingDataResult(std::move(callback)));
  frontend_->ControlRequested(request_id, handle, control_code,
                              ToProtocolBinary(data));
}

void SmartCardEmulationHandler::OnGetAttrib(
    uint32_t handle,
    uint32_t id,
    device::mojom::SmartCardConnection::GetAttribCallback callback) {
  std::string request_id = GenerateRequestId();

  AddPendingRequest(request_id, PendingDataResult(std::move(callback)));

  frontend_->GetAttribRequested(request_id, handle, id);
}

void SmartCardEmulationHandler::OnTransmit(
    uint32_t handle,
    device::mojom::SmartCardProtocol protocol,
    const std::vector<uint8_t>& data,
    device::mojom::SmartCardConnection::TransmitCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingDataResult(std::move(callback)));
  frontend_->TransmitRequested(request_id, handle, ToProtocolBinary(data),
                               ToProtocolSmartCardProtocol(protocol));
}

void SmartCardEmulationHandler::OnStatus(
    uint32_t handle,
    device::mojom::SmartCardConnection::StatusCallback callback) {
  std::string request_id = GenerateRequestId();

  AddPendingRequest(request_id, PendingStatus(std::move(callback)));

  frontend_->StatusRequested(request_id, handle);
}

void SmartCardEmulationHandler::OnSetAttrib(
    uint32_t handle,
    uint32_t id,
    const std::vector<uint8_t>& data,
    device::mojom::SmartCardConnection::SetAttribCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingPlainResult(std::move(callback)));
  frontend_->SetAttribRequested(request_id, handle, id,
                                std::move(ToProtocolBinary(data)));
}

void SmartCardEmulationHandler::OnBeginTransaction(
    uint32_t handle,
    device::mojom::SmartCardConnection::BeginTransactionCallback callback) {
  std::string request_id = GenerateRequestId();

  AddPendingRequest(request_id, PendingBeginTransaction(std::move(callback)));

  frontend_->BeginTransactionRequested(request_id, handle);
}

void SmartCardEmulationHandler::OnEndTransaction(
    uint32_t handle,
    device::mojom::SmartCardDisposition disposition,
    device::mojom::SmartCardTransaction::EndTransactionCallback callback) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingPlainResult(std::move(callback)));
  frontend_->EndTransactionRequested(request_id, handle,
                                     ToProtocolDisposition(disposition));
}

void SmartCardEmulationHandler::OnReleaseContext(uint32_t context_id) {
  std::string request_id = GenerateRequestId();
  AddPendingRequest(request_id, PendingReleaseContext());
  frontend_->ReleaseContextRequested(request_id, context_id);
}

}  // namespace content::protocol
