// 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:freezed_annotation/freezed_annotation.dart' hide protected;
import 'package:localsend_isolates/rust/api/model.dart';
import 'package:localsend_isolates/rust/frb_generated.dart';

part 'server.freezed.dart';

// These functions are ignored because they are not marked as `pub`: `handle_server_event`, `handle_web_event`, `recv_opt`, `resolve_file_content`, `resolve_upload_target`

/// Starts the HTTP server on the given port (IPv4 and IPv6).
/// The server runs until [RsHttpServer::stop] is called.
///
/// Passing [web_send] additionally enables the web send (download API) so that
/// web browsers can download the offered files.
///
/// Passing [show_token] enables the internal `show` endpoint that lets another
/// application instance request this one to show itself (emitted as
/// [RsServerEvent::Show]). The token guards the endpoint against other clients.
///
/// Events are received by listening to [RsHttpServer::listen].
Future<RsHttpServer> startServer({
  required int port,
  TlsConfig? tls,
  required String alias,
  required String version,
  String? deviceModel,
  DeviceType? deviceType,
  required String fingerprint,
  String? pin,
  WebSendParams? webSend,
  String? showToken,
}) => RustLib.instance.api.crateApiServerStartServer(
  port: port,
  tls: tls,
  alias: alias,
  version: version,
  deviceModel: deviceModel,
  deviceType: deviceType,
  fingerprint: fingerprint,
  pin: pin,
  webSend: webSend,
  showToken: showToken,
);

// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<RsHttpServer>>
abstract class RsHttpServer implements RustOpaqueInterface {
  /// Cancels the active upload session, e.g. because the user aborted the
  /// transfer on the receiving side.
  ///
  /// Uploads that are already in progress still run to completion, but new
  /// upload requests are rejected and a new session can be created.
  /// No [RsServerEvent::SessionEnd] is emitted: the application initiated
  /// the cancellation itself.
  Future<void> cancelSession({required String sessionId});

  /// Emits server events until the server is stopped.
  /// Can only be listened to once.
  ///
  /// The v2 protocol, the web send (download API), and the internal endpoint
  /// events are all emitted on the same stream.
  Stream<RsServerEvent> listen();

  /// Rejects the pending [RsServerEvent::WebFileDownload] event, e.g. because
  /// the application failed to resolve a source for the file content.
  ///
  /// The download request fails with an error response.
  /// Does nothing if the download was already answered.
  Future<void> rejectFileDownload({required String sessionId, required String fileId});

  /// Rejects the pending [RsServerEvent::FileUpload] event, e.g. because
  /// the application failed to prepare a save target for the file.
  ///
  /// The upload request fails with an error response and the file is marked
  /// as failed. Does nothing if the upload was already answered.
  Future<void> rejectFileUpload({required String sessionId, required String fileId});

  /// Answers the pending [RsServerEvent::WebFileDownload] event with the source
  /// the file content should be read from (either a path or a file descriptor).
  ///
  /// The server reads the content and streams it to the web client.
  Future<void> respondFileDownload({required String sessionId, required String fileId, String? path, int? fileDescriptor});

  /// Answers the pending [RsServerEvent::FileUpload] event with the target
  /// the file should be saved to (either a path or a file descriptor)
  /// and waits until the file has been received completely.
  ///
  /// The progress (fraction of [file_size]) is emitted on [sink]
  /// while the file is being received.
  Stream<double> respondFileUpload({required String sessionId, required String fileId, String? path, int? fileDescriptor, required BigInt fileSize});

  /// Answers the pending [RsServerEvent::WebPrepareDownload] event.
  ///
  /// Passing `true` accepts the download request, `false` declines it.
  Future<void> respondPrepareDownload({required String sessionId, required bool accept});

  /// Answers the pending [RsServerEvent::PrepareUpload] event.
  ///
  /// Passing the accepted file IDs (a subset of the offered files) accepts the request.
  /// Passing `None` declines the request.
  Future<void> respondPrepareUpload({List<String>? acceptedFileIds});

  /// Stops the server.
  /// Returns after the listeners are closed, so the port can be bound again.
  Future<void> stop();
}

enum ProtocolTypeV2 {
  http,
  https,
}

class RegisterDtoV2 {
  final String alias;
  final String version;
  final String? deviceModel;
  final DeviceType? deviceType;
  final String fingerprint;
  final int port;
  final ProtocolTypeV2 protocol;
  final bool download;

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

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

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

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

  /// A device registered itself via `POST /api/localsend/v2/register`.
  ///
  /// On TLS, this event is only emitted when `info.fingerprint` matches the
  /// fingerprint of the client certificate verified during the mTLS
  /// handshake, so the fingerprint cannot be spoofed.
  const factory RsServerEvent.register({
    required String ip,
    required RegisterDtoV2 info,
  }) = RsServerEvent_Register;

  /// A sender requests to upload files via `POST /api/localsend/v2/prepare-upload`.
  const factory RsServerEvent.prepareUpload({
    /// The session ID the upload session will have when the request is accepted.
    required String sessionId,
    required String ip,
    required RegisterDtoV2 info,

    /// The SHA-256 fingerprint (uppercase hex) of the sender's client
    /// certificate verified during the mTLS handshake. Unlike
    /// `info.fingerprint`, this value cannot be spoofed.
    /// `None` when the server runs without TLS.
    String? certFingerprint,
    required Map<String, FileDto> files,
  }) = RsServerEvent_PrepareUpload;

  /// An accepted file is being uploaded via `POST /api/localsend/v2/upload`.
  const factory RsServerEvent.fileUpload({
    required String sessionId,
    required String fileId,
    required FileDto file,
  }) = RsServerEvent_FileUpload;

  /// An upload session ended.
  const factory RsServerEvent.sessionEnd({
    required String sessionId,
    required SessionEndReasonV2 reason,
  }) = RsServerEvent_SessionEnd;

  /// A prepare-upload request was aborted before a session was created,
  /// e.g. the sender disconnected while the application was still deciding.
  /// The [RsServerEvent::PrepareUpload] with the same session ID
  /// no longer needs to be answered.
  const factory RsServerEvent.prepareUploadAborted({
    required String sessionId,
  }) = RsServerEvent_PrepareUploadAborted;

  /// `POST /api/localsend/v2/cancel` was received for a session this server
  /// does not manage: the remote device cancels a transfer this application
  /// is currently *sending* to it. The application must verify that [ip]
  /// matches the target of the send session before cancelling it.
  const factory RsServerEvent.cancelReceived({
    required String ip,
    required String sessionId,
  }) = RsServerEvent_CancelReceived;

  /// A web client requests to download the shared files via `POST /api/localsend/v2/prepare-download`.
  ///
  /// Must be answered with [RsHttpServer::respond_prepare_download].
  const factory RsServerEvent.webPrepareDownload({
    required String ip,
    required String sessionId,
    String? userAgent,
  }) = RsServerEvent_WebPrepareDownload;

  /// A web client downloads an offered file via `GET /api/localsend/v2/download`.
  ///
  /// Must be answered with [RsHttpServer::respond_file_download].
  const factory RsServerEvent.webFileDownload({
    required String sessionId,
    required String fileId,
    required FileDto file,
  }) = RsServerEvent_WebFileDownload;

  /// Another application instance requested the running application to show itself
  /// via `POST /api/localsend/v2/show`.
  const factory RsServerEvent.show_({
    /// Command-line arguments forwarded by the other application instance.
    required List<String> args,
  }) = RsServerEvent_Show;
}

enum SessionEndReasonV2 {
  finished,
  cancelled,
}

class TlsConfig {
  final String cert;
  final String privateKey;

  const TlsConfig({
    required this.cert,
    required this.privateKey,
  });

  @override
  int get hashCode => cert.hashCode ^ privateKey.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) || other is TlsConfig && runtimeType == other.runtimeType && cert == other.cert && privateKey == other.privateKey;
}

class WebSendI18n {
  final String waiting;
  final String enterPin;
  final String invalidPin;
  final String tooManyAttempts;
  final String rejected;
  final String files;
  final String fileName;
  final String size;

  const WebSendI18n({
    required this.waiting,
    required this.enterPin,
    required this.invalidPin,
    required this.tooManyAttempts,
    required this.rejected,
    required this.files,
    required this.fileName,
    required this.size,
  });

  @override
  int get hashCode =>
      waiting.hashCode ^
      enterPin.hashCode ^
      invalidPin.hashCode ^
      tooManyAttempts.hashCode ^
      rejected.hashCode ^
      files.hashCode ^
      fileName.hashCode ^
      size.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is WebSendI18n &&
          runtimeType == other.runtimeType &&
          waiting == other.waiting &&
          enterPin == other.enterPin &&
          invalidPin == other.invalidPin &&
          tooManyAttempts == other.tooManyAttempts &&
          rejected == other.rejected &&
          files == other.files &&
          fileName == other.fileName &&
          size == other.size;
}

/// Configuration for web send: files offered for download by web browsers.
///
/// Web send can be enabled independently of the v2 protocol endpoints. When
/// omitted, the download API responds with 403 and only the v2 endpoints run.
class WebSendParams {
  /// The metadata of the files offered for download, mapped by file ID.
  /// The content is requested per download via [RsServerEvent::WebFileDownload].
  final Map<String, FileDto> files;

  /// Optional PIN that web clients must provide via the `pin` query parameter.
  final String? pin;

  /// Translations for the web page, served via `/i18n.json`.
  final WebSendI18n i18N;

  const WebSendParams({
    required this.files,
    this.pin,
    required this.i18N,
  });

  @override
  int get hashCode => files.hashCode ^ pin.hashCode ^ i18N.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is WebSendParams && runtimeType == other.runtimeType && files == other.files && pin == other.pin && i18N == other.i18N;
}
