// 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 'frb_generated.dart';
import 'lib.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
part 'api.freezed.dart';

// These functions are ignored because they are not marked as `pub`: `log_sink`, `runtime`, `session`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `clone`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `from`, `from`, `from`, `from`, `from`, `from`

/// Connect to a TeamSpeak-compatible server and return the initial
/// state snapshot. Honours the DEC-006 single-connection invariant
/// via [`BridgeError::AlreadyConnected`].
///
/// `password` is optional — pass an empty string for servers that
/// don't require one.
Future<BridgeSnapshot> connect({
  required String host,
  required String nickname,
  required String password,
}) => RustLib.instance.api.crateApiConnect(
  host: host,
  nickname: nickname,
  password: password,
);

/// Re-fetch a fresh snapshot from the active connection.
Future<BridgeSnapshot> snapshot() => RustLib.instance.api.crateApiSnapshot();

/// Disconnect from the server. No-op if not connected.
Future<void> disconnect() => RustLib.instance.api.crateApiDisconnect();

/// True if a connection is currently active.
Future<bool> isConnected() => RustLib.instance.api.crateApiIsConnected();

/// Start the audio engine on the active connection. Requires a
/// connection; idempotent (will replace any previous engine).
Future<void> startAudio() => RustLib.instance.api.crateApiStartAudio();

/// Set the push-to-talk state.
Future<void> setPtt({required bool active}) =>
    RustLib.instance.api.crateApiSetPtt(active: active);

/// Update the active PTT binding (gen2 v0.9.3 / DEC-026). The
/// platform_key string is opaque to the bridge — it identifies the
/// bound key inside the platform backend and never appears in any
/// log record or diagnostic export (DEC-027 enforced at the
/// diagnostics-sanitizer layer).
Future<void> setPttBinding({
  required BridgePttInputClass inputClass,
  required String platformKey,
}) => RustLib.instance.api.crateApiSetPttBinding(
  inputClass: inputClass,
  platformKey: platformKey,
);

/// Read the current PTT capability descriptor. Returns a
/// `(level, backend_id, bound_input_class)` triple matching the
/// privacy-safe `BridgeEvent::PttCapability` event shape; useful
/// for the initial UI render before the first event arrives.
Future<(String, String, String)> pttDescriptor() =>
    RustLib.instance.api.crateApiPttDescriptor();

/// Move our own client to `channel_id`. Optional channel password
/// for password-protected channels — pass an empty string when not
/// required.
Future<void> moveToChannel({
  required BigInt channelId,
  required String password,
}) => RustLib.instance.api.crateApiMoveToChannel(
  channelId: channelId,
  password: password,
);

/// Toggle self input-mute (microphone) on the server. Independent
/// of push-to-talk: a muted client never transmits regardless of
/// PTT state.
Future<void> setInputMuted({required bool muted}) =>
    RustLib.instance.api.crateApiSetInputMuted(muted: muted);

/// Toggle self output-mute (speaker). Mutes locally *and* informs
/// the server. The server uses this for the channel icon next to
/// the client name; the local mute kicks in immediately even
/// before the server acknowledges.
Future<void> setOutputMuted({required bool muted}) =>
    RustLib.instance.api.crateApiSetOutputMuted(muted: muted);

/// Set master output gain. `1.0` is unity, `0.0` is silent. Values
/// above `1.0` amplify and can clip downstream. Errors when audio
/// is not started.
Future<void> setOutputGain({required double gain}) =>
    RustLib.instance.api.crateApiSetOutputGain(gain: gain);

/// User-initiated diagnostic export. Returns a multi-line text
/// blob, redacted per the production policy, that the user can
/// share or copy. DEC-016 forbids automatic uploads — this is the
/// only path that surfaces logs.
String exportDiagnostics() => RustLib.instance.api.crateApiExportDiagnostics();

/// Wire the identity persistence store to a platform-private
/// directory. Should be called once on app start after Flutter has
/// resolved `getApplicationSupportDirectory()` (or equivalent).
///
/// Subsequent [`connect`] calls will reuse the persisted identity,
/// or generate-and-persist a fresh one on first use. This keeps the
/// server-visible UID stable across app restarts.
///
/// Beta caveat: the identity is stored as a plain file (mode 0600
/// on Unix). It is *not* encrypted at rest. RISK-PoC-002 documents
/// this gap; the v0.4 storage rework lands the proper Secret
/// Service + Android Keystore + iOS Keychain backends.
Future<void> initStorage({required String dir}) =>
    RustLib.instance.api.crateApiInitStorage(dir: dir);

/// List persisted bookmarks.
Future<List<BridgeBookmark>> listBookmarks() =>
    RustLib.instance.api.crateApiListBookmarks();

/// Insert a bookmark and return its assigned id. The `id` field on
/// the input is ignored.
Future<PlatformInt64> addBookmark({required BridgeBookmark b}) =>
    RustLib.instance.api.crateApiAddBookmark(b: b);

/// Update an existing bookmark.
Future<void> updateBookmark({required BridgeBookmark b}) =>
    RustLib.instance.api.crateApiUpdateBookmark(b: b);

/// Delete a bookmark by id.
Future<void> deleteBookmark({required PlatformInt64 id}) =>
    RustLib.instance.api.crateApiDeleteBookmark(id: id);

/// Notify the core of the latest OS-reported connectivity state.
/// Called by the Flutter side from `connectivity_plus` callbacks.
/// The core's supervisor uses this to (a) pre-charge the watchdog
/// on Offline and (b) short-circuit reconnect backoff on Online.
void setNetworkState({required BridgeNetworkState state}) =>
    RustLib.instance.api.crateApiSetNetworkState(state: state);

/// Subscribe to lifecycle events. Each call yields a fresh
/// subscription; multiple subscribers are supported. On slow
/// consumers, events are dropped rather than blocking the supervisor
/// (consistent with `tokio::sync::broadcast::Receiver` semantics).
Stream<BridgeEvent> eventsStream() =>
    RustLib.instance.api.crateApiEventsStream();

/// Read audio statistics. Errors if no connection or audio not started.
Future<BridgeAudioStats> audioStats() =>
    RustLib.instance.api.crateApiAudioStats();

/// Statistics from the audio engine.
class BridgeAudioStats {
  /// Number of Opus frames sent since audio started.
  final int framesSent;

  /// Number of inbound voice packets decoded.
  final int framesReceived;

  /// Current push-to-talk state.
  final bool pttActive;

  const BridgeAudioStats({
    required this.framesSent,
    required this.framesReceived,
    required this.pttActive,
  });

  @override
  int get hashCode =>
      framesSent.hashCode ^ framesReceived.hashCode ^ pttActive.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is BridgeAudioStats &&
          runtimeType == other.runtimeType &&
          framesSent == other.framesSent &&
          framesReceived == other.framesReceived &&
          pttActive == other.pttActive;
}

/// Bookmark DTO mirroring [`chanora_core::Bookmark`].
class BridgeBookmark {
  /// Row id assigned by SQLite. Use `0` when adding new rows;
  /// the returned id is then meaningful.
  final PlatformInt64 id;

  /// User-facing label.
  final String displayName;

  /// `hostname[:port]` or TSDNS name.
  final String host;

  /// Nickname to use for this bookmark.
  final String nickname;

  /// Optional remembered password. Empty string = none.
  final String password;

  const BridgeBookmark({
    required this.id,
    required this.displayName,
    required this.host,
    required this.nickname,
    required this.password,
  });

  @override
  int get hashCode =>
      id.hashCode ^
      displayName.hashCode ^
      host.hashCode ^
      nickname.hashCode ^
      password.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is BridgeBookmark &&
          runtimeType == other.runtimeType &&
          id == other.id &&
          displayName == other.displayName &&
          host == other.host &&
          nickname == other.nickname &&
          password == other.password;
}

/// Channel as seen by Dart. Matches `chanora_protocol::ChannelInfo`
/// but with primitive `u64` ids so the Dart side gets `BigInt`s
/// without any wrapper-type ceremony.
class BridgeChannel {
  /// Stable channel id.
  final BigInt id;

  /// Parent channel id; 0 means top-level.
  final BigInt parent;

  /// Display name.
  final String name;

  /// Server-side ordering hint.
  final PlatformInt64 order;

  const BridgeChannel({
    required this.id,
    required this.parent,
    required this.name,
    required this.order,
  });

  @override
  int get hashCode =>
      id.hashCode ^ parent.hashCode ^ name.hashCode ^ order.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is BridgeChannel &&
          runtimeType == other.runtimeType &&
          id == other.id &&
          parent == other.parent &&
          name == other.name &&
          order == other.order;
}

/// Client as seen by Dart.
class BridgeClient {
  /// Stable client id.
  final BigInt id;

  /// Channel id the client is currently in.
  final BigInt channel;

  /// Nickname.
  final String name;

  const BridgeClient({
    required this.id,
    required this.channel,
    required this.name,
  });

  @override
  int get hashCode => id.hashCode ^ channel.hashCode ^ name.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is BridgeClient &&
          runtimeType == other.runtimeType &&
          id == other.id &&
          channel == other.channel &&
          name == other.name;
}

@freezed
sealed class BridgeEvent with _$BridgeEvent {
  const BridgeEvent._();

  /// Initial connect succeeded, or a reconnect attempt succeeded.
  const factory BridgeEvent.connected({
    /// Server name reported by the server snapshot.
    required String serverName,
  }) = BridgeEvent_Connected;

  /// Connection lost; supervisor will retry.
  const factory BridgeEvent.lost({
    /// Reason classification from the protocol layer.
    required String reason,
  }) = BridgeEvent_Lost;

  /// Supervisor is sleeping before its next reconnect attempt.
  const factory BridgeEvent.reconnecting({
    /// 1-based attempt counter for the current outage.
    required int attempt,

    /// Seconds the supervisor will sleep before this attempt.
    required int delaySecs,
  }) = BridgeEvent_Reconnecting;

  /// Session ended (user-requested disconnect or unrecoverable).
  const factory BridgeEvent.disconnected({
    /// Reason classification.
    required String reason,
  }) = BridgeEvent_Disconnected;

  /// Audio engine started.
  const factory BridgeEvent.audioStarted() = BridgeEvent_AudioStarted;

  /// Audio engine stopped.
  const factory BridgeEvent.audioStopped() = BridgeEvent_AudioStopped;

  /// Snapshot probe observed a change in channel/client counts.
  /// UI uses this to drive an auto-refresh without active
  /// polling.
  const factory BridgeEvent.snapshotChanged({
    /// Latest channel count.
    required int channels,

    /// Latest client count.
    required int clients,
  }) = BridgeEvent_SnapshotChanged;

  /// Detected desktop Push-to-Talk capability (gen2 v0.9.3,
  /// DEC-023..028). The fields carry only privacy-safe values per
  /// DEC-027: the capability level, a stable backend identifier,
  /// and the bound input class. No key codes, scan codes, or
  /// virtual-key values cross this boundary.
  const factory BridgeEvent.pttCapability({
    /// Stable capability identifier (`"L0Focused"`,
    /// `"L1GlobalShortcut"`, `"L2GlobalHoldToTalk"`,
    /// `"L3GlobalWithMouseButtons"`, or `"L4DeviceAware"`).
    required String level,

    /// Stable backend identifier (e.g. `"focused"`).
    required String backendId,

    /// Coarse bound input class (e.g. `"keyboard"`,
    /// `"mouse-side-button"`); empty when no binding is active.
    required String boundInputClass,
  }) = BridgeEvent_PttCapability;
}

/// Coarse OS-reported network state. Mirrors
/// [`chanora_core::NetworkState`] across the bridge.
enum BridgeNetworkState {
  /// No signal seen yet.
  unknown,

  /// OS reports a usable network.
  online,

  /// OS reports no network.
  offline,
}

/// Coarse PTT input class (gen2 v0.9.3 / DEC-026). Stable strings;
/// the bridge never carries raw key codes.
enum BridgePttInputClass {
  /// No binding is active.
  none,

  /// A keyboard key.
  keyboard,

  /// A mouse side button (Mouse4 / Mouse5).
  mouseSideButton,
}

/// Server snapshot as seen by Dart.
class BridgeSnapshot {
  /// Server name.
  final String serverName;

  /// Welcome banner text.
  final String welcomeMessage;

  /// Server platform (e.g. "Linux").
  final String platform;

  /// Server version string.
  final String version;

  /// Channels currently known.
  final List<BridgeChannel> channels;

  /// Clients currently known.
  final List<BridgeClient> clients;

  const BridgeSnapshot({
    required this.serverName,
    required this.welcomeMessage,
    required this.platform,
    required this.version,
    required this.channels,
    required this.clients,
  });

  @override
  int get hashCode =>
      serverName.hashCode ^
      welcomeMessage.hashCode ^
      platform.hashCode ^
      version.hashCode ^
      channels.hashCode ^
      clients.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is BridgeSnapshot &&
          runtimeType == other.runtimeType &&
          serverName == other.serverName &&
          welcomeMessage == other.welcomeMessage &&
          platform == other.platform &&
          version == other.version &&
          channels == other.channels &&
          clients == other.clients;
}
