// This file is automatically generated, so please do not edit it.
// @generated by `flutter_rust_bridge`@ 2.12.0.

// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import

import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:localsend_isolates/rust/api/model.dart';
import 'package:localsend_isolates/rust/frb_generated.dart';

// These functions are ignored because they are not marked as `pub`: `rs_stored_device`, `stop`
// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `DiscoveryInstance`

/// Starts the discovery: binds the UDP multicast sockets on all usable
/// network interfaces, answers announcements of other devices with an HTTP
/// register request, and keeps the store of confirmed devices.
///
/// Announcements are received from the IPv4 [group] and, as a LocalSend
/// extension, from the (currently hardcoded) IPv6 group `ff12::fd3a:e420`.
///
/// [port] is used both to bind the multicast sockets and as the HTTP server
/// port announced to other devices. [cert_pem] and [private_key_pem] are this
/// device's TLS identity, sent as client certificate with every register
/// request; [fingerprint] must be the certificate's SHA-256 fingerprint.
///
/// Nothing is announced until [RsDiscovery::announce] is called.
///
/// Cannot fail besides an invalid [group]: when no multicast socket could be
/// bound (e.g. the port is taken by another process), discovery still runs
/// without multicast — see [RsDiscovery::multicast_error] — and still learns
/// about devices through [RsDiscovery::discover], [RsDiscovery::scan_subnet]
/// and [RsDiscovery::add_device].
Future<RsDiscovery> startDiscovery({
  required String group,
  required int port,
  List<String>? networkWhitelist,
  List<String>? networkBlacklist,
  required String alias,
  required String version,
  String? deviceModel,
  DeviceType? deviceType,
  required String fingerprint,
  required ProtocolType protocol,
  required bool download,
  required String certPem,
  required String privateKeyPem,
  required BigInt timeoutMs,
}) => RustLib.instance.api.crateApiDiscoveryStartDiscovery(
  group: group,
  port: port,
  networkWhitelist: networkWhitelist,
  networkBlacklist: networkBlacklist,
  alias: alias,
  version: version,
  deviceModel: deviceModel,
  deviceType: deviceType,
  fingerprint: fingerprint,
  protocol: protocol,
  download: download,
  certPem: certPem,
  privateKeyPem: privateKeyPem,
  timeoutMs: timeoutMs,
);

// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsDiscovery>>
abstract class RsDiscovery implements RustOpaqueInterface {
  /// Puts a device confirmed outside of the discovery into the store, e.g.
  /// one that answered an announcement by registering with this device's
  /// HTTP server. The device is emitted on [RsDiscovery::listen].
  Future<void> addDevice({required RsDiscoveredDevice device});

  /// Announces this device to the network, which makes every other LocalSend
  /// device on it register with this device over HTTP.
  ///
  /// Devices registering in response arrive at the application as server
  /// events, not here: feed them back via [RsDiscovery::add_device].
  ///
  /// Returns once the whole announcement burst has been sent, which takes a
  /// few seconds, or immediately once the discovery has been stopped or
  /// multicast is unavailable.
  Future<void> announce();

  /// Discovers a device at a known address, e.g. a favorite or a peer that
  /// multicast does not reach, by sending it a register request.
  ///
  /// The confirmed device is also emitted on [RsDiscovery::listen].
  /// Returns `None` when the device did not answer or answered with this
  /// device's own fingerprint (i.e. the device discovered itself).
  Future<RsStoredDevice?> discover({required String host, required int port, required ProtocolType protocol});

  /// Emits a [RsStoredDevice] for every device confirmation until the
  /// discovery is stopped. Can only be listened to once.
  ///
  /// Also returns when the Dart side of the stream is gone (e.g. after a
  /// hot restart), so this call does not keep the discovery alive forever.
  Stream<RsStoredDevice> listen();

  /// The reason the multicast sockets could not be bound, when they could
  /// not. Discovery then neither hears nor sends announcements.
  Future<String?> multicastError();

  /// Scans the `/24` subnet of the local interface address [interface_ip]
  /// by sending every other host a register request, for networks that do
  /// not carry multicast.
  ///
  /// The found devices are emitted on [RsDiscovery::listen] as they answer;
  /// this method returns once the whole scan has finished. At most one scan
  /// runs per interface: a call for an address that is still being scanned
  /// returns immediately.
  Future<void> scanSubnet({required String interfaceIp, required int port, required ProtocolType protocol});

  /// Sets whether announcements of other devices are answered with a
  /// register request (the answer is what makes the announcing device enter
  /// the store). On by default.
  ///
  /// Turned off while the HTTP server is not running: the answer would
  /// advertise a port that nobody listens on.
  Future<void> setAnswerAnnouncements({required bool answer});

  /// Stops the discovery, which also ends the [RsDiscovery::listen] stream.
  /// Returns after all sockets are closed, so the port can be bound again.
  Future<void> stop();
}

/// An address a stored device was confirmed on and is dialed at.
class RsDeviceChannel {
  /// The host to dial: an IP address, or the scoped form `fe80::1%3` for
  /// link-local IPv6 (the Rust HTTP client accepts both back as a host).
  final String host;

  /// The port of the device's HTTP server at this address.
  final int port;
  final ProtocolType protocol;

  const RsDeviceChannel({
    required this.host,
    required this.port,
    required this.protocol,
  });

  @override
  int get hashCode => host.hashCode ^ port.hashCode ^ protocol.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is RsDeviceChannel && runtimeType == other.runtimeType && host == other.host && port == other.port && protocol == other.protocol;
}

/// A single device confirmation over HTTP, fed into the store via
/// [RsDiscovery::add_device]: the device's register request was accepted by
/// our server, so it is known to be reachable at [RsDiscoveredDevice::host].
class RsDiscoveredDevice {
  final String alias;

  /// Protocol version (major.minor) implemented by the device.
  final String version;
  final String? deviceModel;
  final DeviceType? deviceType;

  /// Fingerprint identifying the device; devices are deduplicated by it.
  final String fingerprint;

  /// The host the device was confirmed on: an IP address, or the scoped
  /// form `fe80::1%3` for link-local IPv6 (the Rust HTTP client accepts
  /// both back as a host).
  final String host;

  /// The port of the device's HTTP server.
  final int port;
  final ProtocolType protocol;

  /// Whether the device's download API is active.
  final bool download;

  const RsDiscoveredDevice({
    required this.alias,
    required this.version,
    this.deviceModel,
    this.deviceType,
    required this.fingerprint,
    required this.host,
    required this.port,
    required this.protocol,
    required this.download,
  });

  @override
  int get hashCode =>
      alias.hashCode ^
      version.hashCode ^
      deviceModel.hashCode ^
      deviceType.hashCode ^
      fingerprint.hashCode ^
      host.hashCode ^
      port.hashCode ^
      protocol.hashCode ^
      download.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is RsDiscoveredDevice &&
          runtimeType == other.runtimeType &&
          alias == other.alias &&
          version == other.version &&
          deviceModel == other.deviceModel &&
          deviceType == other.deviceType &&
          fingerprint == other.fingerprint &&
          host == other.host &&
          port == other.port &&
          protocol == other.protocol &&
          download == other.download;
}

/// The merged stored state of a discovered device: one entry per fingerprint,
/// carrying every address the device was confirmed on. A multi-homed device
/// that is reachable over several network interfaces is still one
/// [RsStoredDevice].
///
/// Emitted on [RsDiscovery::listen] for every confirmation (answered
/// announcements, scan results and devices fed in via
/// [RsDiscovery::add_device]), so a device re-appears — with its channels
/// accumulated so far — whenever it re-announces itself or is re-discovered.
class RsStoredDevice {
  final String alias;

  /// Protocol version (major.minor) implemented by the device.
  final String version;
  final String? deviceModel;
  final DeviceType? deviceType;

  /// Fingerprint identifying the device; devices are deduplicated by it.
  final String fingerprint;

  /// Whether the device's download API is active.
  final bool download;

  /// Every address the device was confirmed on, best first (available
  /// before not-reachable, IPv6 before IPv4, most recently confirmed
  /// first). Never empty: a device only enters the store through a
  /// confirmation.
  final List<RsDeviceChannel> channels;

  const RsStoredDevice({
    required this.alias,
    required this.version,
    this.deviceModel,
    this.deviceType,
    required this.fingerprint,
    required this.download,
    required this.channels,
  });

  @override
  int get hashCode =>
      alias.hashCode ^ version.hashCode ^ deviceModel.hashCode ^ deviceType.hashCode ^ fingerprint.hashCode ^ download.hashCode ^ channels.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is RsStoredDevice &&
          runtimeType == other.runtimeType &&
          alias == other.alias &&
          version == other.version &&
          deviceModel == other.deviceModel &&
          deviceType == other.deviceType &&
          fingerprint == other.fingerprint &&
          download == other.download &&
          channels == other.channels;
}
