import 'package:flutter_test/flutter_test.dart';
import 'dart:io' show Platform;

import 'package:chanora_flutter/src/rust/api.dart' as rust;
import 'package:chanora_flutter/widgets/audio_processing_config_state.dart';

void main() {
  const baseConfig = rust.BridgeAudioProcessingConfig(
    route: rust.BridgeAudioRoute.unknown,
    iosMode: rust.BridgeIosVoiceProcessingMode.platformVoiceProcessing,
    processingBackend: rust.BridgeAudioBackend.platformVoiceProcessing,
    vadBackend: rust.BridgeVadBackend.disabled,
    aec: rust.BridgeEffectOwner.platform,
    ns: rust.BridgeEffectOwner.off,
    agc: rust.BridgeEffectOwner.webrtcApm,
    hpfEnabled: true,
    limiterEnabled: false,
    vadHangoverMs: 500,
    vadPreRollMs: 160,
    vadMinTxMs: 200,
    debugWavDumpEnabled: true,
  );

  test('normalizes hidden disabled VAD backend to Silero for UI state', () {
    final state = AudioProcessingConfigState.fromConfig(baseConfig);

    expect(state.vadBackend, rust.BridgeVadBackend.sileroOnnx);
    expect(state.preferHardware, isTrue);
    expect(state.nsEnabled, isFalse);
    expect(state.aecEnabled, isTrue);
    expect(state.agcEnabled, isTrue);
  });

  test('normalizes desktop VAD backend to Silero', () {
    expect(
      normalizedVadBackend(
        rust.BridgeVadBackend.webrtcVad,
        isWindows: true,
        isLinux: false,
      ),
      rust.BridgeVadBackend.sileroOnnx,
    );
    expect(
      normalizedVadBackend(
        rust.BridgeVadBackend.webrtcVad,
        isWindows: false,
        isLinux: true,
      ),
      rust.BridgeVadBackend.sileroOnnx,
    );
  });

  test('default config matches the current platform fallback', () {
    final fallback = defaultAudioProcessingConfig();
    final desktop = Platform.isWindows || Platform.isLinux;

    expect(
      fallback.processingBackend,
      desktop
          ? rust.BridgeAudioBackend.webrtcApm
          : rust.BridgeAudioBackend.platformVoiceProcessing,
    );
    expect(fallback.vadBackend, rust.BridgeVadBackend.sileroOnnx);
    expect(
      fallback.aec,
      desktop
          ? rust.BridgeEffectOwner.webrtcApm
          : rust.BridgeEffectOwner.platform,
    );
    expect(
      fallback.ns,
      desktop
          ? rust.BridgeEffectOwner.webrtcApm
          : rust.BridgeEffectOwner.platform,
    );
    expect(
      fallback.agc,
      desktop
          ? rust.BridgeEffectOwner.webrtcApm
          : rust.BridgeEffectOwner.platform,
    );
  });

  test('builds Android hardware config consistently', () {
    final state = AudioProcessingConfigState.fromConfig(baseConfig)
      ..preferHardware = true
      ..nsEnabled = true
      ..aecEnabled = false
      ..agcEnabled = true;

    final config = state.buildConfig(base: baseConfig, isAndroid: true);

    expect(
      config.processingBackend,
      rust.BridgeAudioBackend.platformVoiceProcessing,
    );
    expect(config.vadBackend, rust.BridgeVadBackend.sileroOnnx);
    expect(config.aec, rust.BridgeEffectOwner.off);
    expect(config.ns, rust.BridgeEffectOwner.platform);
    expect(config.agc, rust.BridgeEffectOwner.platform);
    expect(config.debugWavDumpEnabled, isTrue);
  });

  test('builds Windows/Linux software WebRTC APM config consistently', () {
    final state = AudioProcessingConfigState.fromConfig(baseConfig)
      ..nsEnabled = true
      ..aecEnabled = false
      ..agcEnabled = true;

    final windowsConfig = state.buildConfig(
      base: baseConfig,
      isAndroid: false,
      isIos: false,
      isMacOS: false,
      isWindows: true,
      isLinux: false,
    );

    final linuxConfig = state.buildConfig(
      base: baseConfig,
      isAndroid: false,
      isIos: false,
      isMacOS: false,
      isWindows: false,
      isLinux: true,
    );

    for (final config in [windowsConfig, linuxConfig]) {
      expect(config.processingBackend, rust.BridgeAudioBackend.webrtcApm);
      expect(config.vadBackend, rust.BridgeVadBackend.sileroOnnx);
      expect(config.aec, rust.BridgeEffectOwner.off);
      expect(config.ns, rust.BridgeEffectOwner.webrtcApm);
      expect(config.agc, rust.BridgeEffectOwner.webrtcApm);
      expect(config.debugWavDumpEnabled, isTrue);
    }
  });

  test('normalizes hidden iOS sonora config back to platform VPIO', () {
    const sonoraConfig = rust.BridgeAudioProcessingConfig(
      route: rust.BridgeAudioRoute.unknown,
      iosMode: rust.BridgeIosVoiceProcessingMode.sonoraExperimental,
      processingBackend: rust.BridgeAudioBackend.webrtcApm,
      vadBackend: rust.BridgeVadBackend.disabled,
      aec: rust.BridgeEffectOwner.webrtcApm,
      ns: rust.BridgeEffectOwner.webrtcApm,
      agc: rust.BridgeEffectOwner.webrtcApm,
      hpfEnabled: true,
      limiterEnabled: false,
      vadHangoverMs: 500,
      vadPreRollMs: 160,
      vadMinTxMs: 200,
      debugWavDumpEnabled: true,
    );

    final state = AudioProcessingConfigState.fromConfig(sonoraConfig);
    final config = state.buildConfig(
      base: sonoraConfig,
      isAndroid: false,
      isIos: true,
      isMacOS: false,
      isWindows: false,
      isLinux: false,
    );

    expect(
      state.iosMode,
      rust.BridgeIosVoiceProcessingMode.platformVoiceProcessing,
    );
    expect(
      config.iosMode,
      rust.BridgeIosVoiceProcessingMode.platformVoiceProcessing,
    );
    expect(
      config.processingBackend,
      rust.BridgeAudioBackend.platformVoiceProcessing,
    );
    expect(config.aec, rust.BridgeEffectOwner.platform);
    expect(config.ns, rust.BridgeEffectOwner.platform);
    expect(config.agc, rust.BridgeEffectOwner.platform);
  });

  test(
    'Android hardware mode keeps controls visible because stages can fall back to WebRTC',
    () {
      final state = AudioProcessingConfigState.fromConfig(baseConfig)
        ..preferHardware = true;

      expect(androidShowsNsControl(state), isTrue);
      expect(androidShowsAecControl(state), isTrue);
      expect(androidShowsAgcControl(state), isTrue);
      expect(androidShowsHpfControl(state), isTrue);
      expect(androidShowsLimiterControl(state), isFalse);
    },
  );

  test('Android software mode shows effective WebRTC APM controls', () {
    final state = AudioProcessingConfigState.fromConfig(baseConfig)
      ..preferHardware = false;

    expect(androidShowsNsControl(state), isTrue);
    expect(androidShowsAecControl(state), isTrue);
    expect(androidShowsAgcControl(state), isTrue);
    expect(androidShowsHpfControl(state), isTrue);
    expect(androidShowsLimiterControl(state), isFalse);
  });
}
