import 'dart:io' show Platform;

import '../src/rust/api.dart' as rust;

/// Fallback audio-processing config used before the bridge can report one.
rust.BridgeAudioProcessingConfig defaultAudioProcessingConfig() {
  final desktopWebrtcApm = Platform.isWindows || Platform.isLinux;
  return rust.BridgeAudioProcessingConfig(
    route: rust.BridgeAudioRoute.unknown,
    iosMode: rust.BridgeIosVoiceProcessingMode.platformVoiceProcessing,
    processingBackend: desktopWebrtcApm
        ? rust.BridgeAudioBackend.webrtcApm
        : rust.BridgeAudioBackend.platformVoiceProcessing,
    vadBackend: rust.BridgeVadBackend.sileroOnnx,
    aec: desktopWebrtcApm
        ? rust.BridgeEffectOwner.webrtcApm
        : rust.BridgeEffectOwner.platform,
    ns: desktopWebrtcApm
        ? rust.BridgeEffectOwner.webrtcApm
        : rust.BridgeEffectOwner.platform,
    agc: desktopWebrtcApm
        ? rust.BridgeEffectOwner.webrtcApm
        : rust.BridgeEffectOwner.platform,
    hpfEnabled: true,
    limiterEnabled: true,
    vadHangoverMs: 500,
    vadPreRollMs: 160,
    vadMinTxMs: 200,
    debugWavDumpEnabled: false,
  );
}

/// Mutable UI state for audio-processing controls.
class AudioProcessingConfigState {
  /// Build control state from a bridge config.
  AudioProcessingConfigState.fromConfig(rust.BridgeAudioProcessingConfig config)
    : nsEnabled = config.ns != rust.BridgeEffectOwner.off,
      aecEnabled = config.aec != rust.BridgeEffectOwner.off,
      agcEnabled = config.agc != rust.BridgeEffectOwner.off,
      hpfEnabled = config.hpfEnabled,
      limiterEnabled = config.limiterEnabled,
      debugWavDump = config.debugWavDumpEnabled,
      preferHardware = _usesPlatformEffects(config),
      vadBackend = normalizedVadBackend(config.vadBackend),
      iosMode = normalizedIosProcessingMode(config.iosMode);

  /// Noise suppression toggle.
  bool nsEnabled;

  /// Echo cancellation toggle.
  bool aecEnabled;

  /// Automatic gain-control toggle.
  bool agcEnabled;

  /// High-pass filter toggle.
  bool hpfEnabled;

  /// Limiter toggle.
  bool limiterEnabled;

  /// Debug WAV dump toggle.
  bool debugWavDump;

  /// Android hardware effects preference.
  bool preferHardware;

  /// Selected VAD backend.
  rust.BridgeVadBackend vadBackend;

  /// Selected iOS processing mode.
  rust.BridgeIosVoiceProcessingMode iosMode;

  /// Build the bridge config represented by this UI state.
  rust.BridgeAudioProcessingConfig buildConfig({
    required rust.BridgeAudioProcessingConfig base,
    bool? isAndroid,
    bool? isIos,
    bool? isMacOS,
    bool? isWindows,
    bool? isLinux,
  }) {
    final android = isAndroid ?? Platform.isAndroid;
    final ios = isIos ?? Platform.isIOS;
    final macOS = isMacOS ?? Platform.isMacOS;
    final windows = isWindows ?? Platform.isWindows;
    final linux = isLinux ?? Platform.isLinux;
    final appleVoiceProcessing = ios || macOS;
    final desktopWebrtcApm = windows || linux;
    final vad = normalizedVadBackend(
      vadBackend,
      isWindows: windows,
      isLinux: linux,
    );

    if (android) {
      final owner = preferHardware
          ? rust.BridgeEffectOwner.platform
          : rust.BridgeEffectOwner.webrtcApm;
      return rust.BridgeAudioProcessingConfig(
        route: base.route,
        iosMode: normalizedIosProcessingMode(iosMode),
        processingBackend: preferHardware
            ? rust.BridgeAudioBackend.platformVoiceProcessing
            : rust.BridgeAudioBackend.webrtcApm,
        vadBackend: vad,
        aec: aecEnabled ? owner : rust.BridgeEffectOwner.off,
        ns: nsEnabled ? owner : rust.BridgeEffectOwner.off,
        agc: agcEnabled ? owner : rust.BridgeEffectOwner.off,
        hpfEnabled: hpfEnabled,
        limiterEnabled: limiterEnabled,
        vadHangoverMs: base.vadHangoverMs,
        vadPreRollMs: base.vadPreRollMs,
        vadMinTxMs: base.vadMinTxMs,
        debugWavDumpEnabled: debugWavDump,
      );
    }

    if (appleVoiceProcessing) {
      return rust.BridgeAudioProcessingConfig(
        route: base.route,
        iosMode: normalizedIosProcessingMode(iosMode),
        processingBackend: rust.BridgeAudioBackend.platformVoiceProcessing,
        vadBackend: vad,
        aec: rust.BridgeEffectOwner.platform,
        ns: rust.BridgeEffectOwner.platform,
        agc: rust.BridgeEffectOwner.platform,
        hpfEnabled: hpfEnabled,
        limiterEnabled: limiterEnabled,
        vadHangoverMs: base.vadHangoverMs,
        vadPreRollMs: base.vadPreRollMs,
        vadMinTxMs: base.vadMinTxMs,
        debugWavDumpEnabled: debugWavDump,
      );
    }

    if (desktopWebrtcApm) {
      final owner = rust.BridgeEffectOwner.webrtcApm;
      return rust.BridgeAudioProcessingConfig(
        route: base.route,
        iosMode: normalizedIosProcessingMode(iosMode),
        processingBackend: rust.BridgeAudioBackend.webrtcApm,
        vadBackend: vad,
        aec: aecEnabled ? owner : rust.BridgeEffectOwner.off,
        ns: nsEnabled ? owner : rust.BridgeEffectOwner.off,
        agc: agcEnabled ? owner : rust.BridgeEffectOwner.off,
        hpfEnabled: hpfEnabled,
        limiterEnabled: limiterEnabled,
        vadHangoverMs: base.vadHangoverMs,
        vadPreRollMs: base.vadPreRollMs,
        vadMinTxMs: base.vadMinTxMs,
        debugWavDumpEnabled: debugWavDump,
      );
    }

    return rust.BridgeAudioProcessingConfig(
      route: base.route,
      iosMode: normalizedIosProcessingMode(iosMode),
      processingBackend: rust.BridgeAudioBackend.platformVoiceProcessing,
      vadBackend: vad,
      aec: rust.BridgeEffectOwner.platform,
      ns: nsEnabled
          ? rust.BridgeEffectOwner.platform
          : rust.BridgeEffectOwner.off,
      agc: agcEnabled
          ? rust.BridgeEffectOwner.platform
          : rust.BridgeEffectOwner.off,
      hpfEnabled: hpfEnabled,
      limiterEnabled: limiterEnabled,
      vadHangoverMs: base.vadHangoverMs,
      vadPreRollMs: base.vadPreRollMs,
      vadMinTxMs: base.vadMinTxMs,
      debugWavDumpEnabled: debugWavDump,
    );
  }
}

bool androidUsesHardwareProcessing(AudioProcessingConfigState state) {
  return state.preferHardware;
}

bool androidShowsNsControl(AudioProcessingConfigState state) {
  return true;
}

bool androidShowsAecControl(AudioProcessingConfigState state) {
  return true;
}

bool androidShowsAgcControl(AudioProcessingConfigState state) {
  return true;
}

bool androidShowsHpfControl(AudioProcessingConfigState state) {
  return true;
}

bool androidShowsLimiterControl(AudioProcessingConfigState state) {
  return false;
}

/// Never leave the UI on the hidden disabled backend.
///
/// Windows and Linux use Silero as the primary VAD; WebRTC is still
/// available internally as a runtime fallback.
rust.BridgeVadBackend normalizedVadBackend(
  rust.BridgeVadBackend backend, {
  bool? isWindows,
  bool? isLinux,
}) {
  final desktop =
      (isWindows ?? Platform.isWindows) || (isLinux ?? Platform.isLinux);
  if (desktop) return rust.BridgeVadBackend.sileroOnnx;
  return backend == rust.BridgeVadBackend.disabled
      ? rust.BridgeVadBackend.sileroOnnx
      : backend;
}

rust.BridgeIosVoiceProcessingMode normalizedIosProcessingMode(
  rust.BridgeIosVoiceProcessingMode mode,
) {
  return mode == rust.BridgeIosVoiceProcessingMode.platformVoiceProcessing
      ? mode
      : rust.BridgeIosVoiceProcessingMode.platformVoiceProcessing;
}

bool _usesPlatformEffects(rust.BridgeAudioProcessingConfig config) {
  return config.aec == rust.BridgeEffectOwner.platform ||
      config.ns == rust.BridgeEffectOwner.platform ||
      config.agc == rust.BridgeEffectOwner.platform;
}
