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

// These functions are ignored because they are not marked as `pub`: `cmd_label`, `drive_upload`, `error_fields`, `map_str`, `wire_json`

/// 96-byte anti-spoof fingerprint (authRequest `mode` / login `chatCacheFingerprint`).
/// signature/dex/so are raw digest bytes, passed in so they can change per app version
Uint8List authMode(
        {required List<int> signature,
        required List<int> dex,
        required List<int> so,
        required PlatformInt64 callsSeed,
        required String deviceId}) =>
    RustLib.instance.api.crateApiSessionAuthMode(
        signature: signature,
        dex: dex,
        so: so,
        callsSeed: callsSeed,
        deviceId: deviceId);

// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<KolibriSession>>
abstract class KolibriSession implements RustOpaqueInterface {
  /// connect + sessionInit handshake
  Future<HandshakeInfo> connect();

  void disconnect();

  /// `wire_log`, if given, gets every packet both ways (requests, pushes,
  /// handshake, ping), across reconnects.
  factory KolibriSession(
          {required SessionOptions options,
          RustStreamSink<WireLogEvent>? wireLog}) =>
      RustLib.instance.api
          .crateApiSessionKolibriSessionNew(options: options, wireLog: wireLog);

  /// keepalive `interactive` flag (foreground/background hint)
  bool pingInteractive();

  /// server pushes; yields until the session is dropped
  Stream<PushEvent> pushes();

  /// awaits the response payload (raw msgpack); errors on server error or timeout
  Future<Uint8List> request({required int opcode, required List<int> payload});

  /// like `request_json`, but reports the packet command and, for an error
  /// packet, its full payload (as tagged JSON) plus extracted message/key —
  /// nothing is thrown, so the host can run its own rules over the error body
  /// (e.g. treat `FAIL_LOGIN_TOKEN`/`FAIL_WRONG_PASSWORD` as expired). Only a
  /// lost connection or timeout comes back as `Err`.
  Future<RequestOutcome> requestFull(
      {required int opcode, required String jsonIn});

  /// JSON in, JSON out: `json_in` becomes msgpack (`{"$bin":"<b64>"}` ->
  /// binary), and the response comes back as JSON.
  Future<String> requestJson({required int opcode, required String jsonIn});

  /// fire-and-forget; returns the seq number
  int send({required int opcode, required List<int> payload});

  /// flip `interactive` on a live session; one ping goes out now so the server
  /// hears it right away
  void setPingInteractive({required bool interactive});

  String state();

  /// generic file upload to a CDN url. streams progress, then Done/Error.
  /// user_agent defaults to the session's handshake device.
  Stream<UploadEvent> uploadFile(
      {required String url,
      required List<int> data,
      required String filename,
      String? userAgent});

  /// like [`Self::upload_file`], but streams the body off disk from `path`
  /// (never loads the whole file into memory).
  Stream<UploadEvent> uploadFilePath(
      {required String url,
      required String path,
      required String filename,
      String? contentType,
      String? connection,
      String? userAgent});

  /// photo upload, multipart/form-data. photoToken comes back in the Done body.
  Stream<UploadEvent> uploadPhoto(
      {required String url,
      required List<int> data,
      required String filename,
      String? userAgent});

  /// like [`Self::upload_photo`], but streams the file part off disk from `path`.
  Stream<UploadEvent> uploadPhotoPath(
      {required String url,
      required String path,
      required String filename,
      String? userAgent});

  /// video upload, parallel resumable chunks. Done{status:200} means success.
  Stream<UploadEvent> uploadVideo(
      {required String url,
      required List<int> data,
      required int chunkSize,
      required int concurrency});

  /// like [`Self::upload_video`], but reads each chunk off disk from `path` on
  /// demand (only one chunk per worker in memory).
  Stream<UploadEvent> uploadVideoPath(
      {required String url,
      required String path,
      required int chunkSize,
      required int concurrency});

  /// HTTP User-Agent derived from the handshake device (opcode 6):
  /// `OKMessages/{appVersion} ({osVersion}; {deviceName}; {screen})`. Same
  /// string media uploads use; suitable for webviews that should look like
  /// the native app.
  String userAgent();
}

/// sessionInit handshake result. `payload` is raw msgpack, `payload_json` the
/// same rendered as JSON (for decoding without a msgpack package).
class HandshakeInfo {
  final PlatformInt64? callsSeed;
  final String? deviceName;
  final Uint8List payload;
  final String payloadJson;

  const HandshakeInfo({
    this.callsSeed,
    this.deviceName,
    required this.payload,
    required this.payloadJson,
  });

  @override
  int get hashCode =>
      callsSeed.hashCode ^
      deviceName.hashCode ^
      payload.hashCode ^
      payloadJson.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is HandshakeInfo &&
          runtimeType == other.runtimeType &&
          callsSeed == other.callsSeed &&
          deviceName == other.deviceName &&
          payload == other.payload &&
          payloadJson == other.payloadJson;
}

/// server push; `payload` is raw msgpack, `payload_json` the same as JSON.
class PushEvent {
  final int opcode;
  final Uint8List payload;
  final String payloadJson;

  const PushEvent({
    required this.opcode,
    required this.payload,
    required this.payloadJson,
  });

  @override
  int get hashCode => opcode.hashCode ^ payload.hashCode ^ payloadJson.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is PushEvent &&
          runtimeType == other.runtimeType &&
          opcode == other.opcode &&
          payload == other.payload &&
          payloadJson == other.payloadJson;
}

/// full request result: `cmd` is the packet command (1=ok, 2=not_found,
/// 3=error), `payload_json` the tagged JSON, `error_*` a server error. A server
/// error is reported here, not thrown.
class RequestOutcome {
  final int cmd;
  final int opcode;
  final String payloadJson;
  final String? errorMessage;
  final String? errorKey;

  const RequestOutcome({
    required this.cmd,
    required this.opcode,
    required this.payloadJson,
    this.errorMessage,
    this.errorKey,
  });

  @override
  int get hashCode =>
      cmd.hashCode ^
      opcode.hashCode ^
      payloadJson.hashCode ^
      errorMessage.hashCode ^
      errorKey.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is RequestOutcome &&
          runtimeType == other.runtimeType &&
          cmd == other.cmd &&
          opcode == other.opcode &&
          payloadJson == other.payloadJson &&
          errorMessage == other.errorMessage &&
          errorKey == other.errorKey;
}

/// device + connection options. device fields feed the sessionInit handshake.
class SessionOptions {
  final String host;
  final int port;
  final String deviceId;
  final String instanceId;
  final String appVersion;
  final PlatformInt64 buildNumber;
  final String deviceType;
  final String osVersion;
  final String timezone;
  final String screen;
  final String pushDeviceType;
  final String arch;
  final String locale;
  final String deviceName;
  final String deviceLocale;
  final PlatformInt64 clientSessionId;
  final BigInt pingIntervalSecs;
  final bool pingInteractive;
  final bool autoReconnect;
  final bool insecureTls;

  /// proxy url `scheme://[user:pass@]host:port` (http/socks5/socks5h), or none
  final String? proxy;

  /// `isPwa` in the handshake userAgent; sent only when set
  final bool? isPwa;

  /// `headerUserAgent` in the handshake userAgent; sent only when set
  final String? headerUserAgent;

  const SessionOptions({
    required this.host,
    required this.port,
    required this.deviceId,
    required this.instanceId,
    required this.appVersion,
    required this.buildNumber,
    required this.deviceType,
    required this.osVersion,
    required this.timezone,
    required this.screen,
    required this.pushDeviceType,
    required this.arch,
    required this.locale,
    required this.deviceName,
    required this.deviceLocale,
    required this.clientSessionId,
    required this.pingIntervalSecs,
    required this.pingInteractive,
    required this.autoReconnect,
    required this.insecureTls,
    this.proxy,
    this.isPwa,
    this.headerUserAgent,
  });

  @override
  int get hashCode =>
      host.hashCode ^
      port.hashCode ^
      deviceId.hashCode ^
      instanceId.hashCode ^
      appVersion.hashCode ^
      buildNumber.hashCode ^
      deviceType.hashCode ^
      osVersion.hashCode ^
      timezone.hashCode ^
      screen.hashCode ^
      pushDeviceType.hashCode ^
      arch.hashCode ^
      locale.hashCode ^
      deviceName.hashCode ^
      deviceLocale.hashCode ^
      clientSessionId.hashCode ^
      pingIntervalSecs.hashCode ^
      pingInteractive.hashCode ^
      autoReconnect.hashCode ^
      insecureTls.hashCode ^
      proxy.hashCode ^
      isPwa.hashCode ^
      headerUserAgent.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is SessionOptions &&
          runtimeType == other.runtimeType &&
          host == other.host &&
          port == other.port &&
          deviceId == other.deviceId &&
          instanceId == other.instanceId &&
          appVersion == other.appVersion &&
          buildNumber == other.buildNumber &&
          deviceType == other.deviceType &&
          osVersion == other.osVersion &&
          timezone == other.timezone &&
          screen == other.screen &&
          pushDeviceType == other.pushDeviceType &&
          arch == other.arch &&
          locale == other.locale &&
          deviceName == other.deviceName &&
          deviceLocale == other.deviceLocale &&
          clientSessionId == other.clientSessionId &&
          pingIntervalSecs == other.pingIntervalSecs &&
          pingInteractive == other.pingInteractive &&
          autoReconnect == other.autoReconnect &&
          insecureTls == other.insecureTls &&
          proxy == other.proxy &&
          isPwa == other.isPwa &&
          headerUserAgent == other.headerUserAgent;
}

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

  const factory UploadEvent.progress({
    required BigInt sent,
    required BigInt total,
  }) = UploadEvent_Progress;
  const factory UploadEvent.done({
    required int status,
    required Uint8List body,
  }) = UploadEvent_Done;
  const factory UploadEvent.error({
    required String message,
  }) = UploadEvent_Error;
}

/// one tapped packet for logs. `direction` "out"/"in", `cmd`
/// "request"/"ok"/"not_found"/"error"/"push", `json` the payload (lossy: binary
/// -> base64).
class WireLogEvent {
  final String direction;
  final String cmd;
  final int opcode;
  final int seq;
  final String json;

  const WireLogEvent({
    required this.direction,
    required this.cmd,
    required this.opcode,
    required this.seq,
    required this.json,
  });

  @override
  int get hashCode =>
      direction.hashCode ^
      cmd.hashCode ^
      opcode.hashCode ^
      seq.hashCode ^
      json.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is WireLogEvent &&
          runtimeType == other.runtimeType &&
          direction == other.direction &&
          cmd == other.cmd &&
          opcode == other.opcode &&
          seq == other.seq &&
          json == other.json;
}
