import 'package:flutter/foundation.dart'
    show TargetPlatform, defaultTargetPlatform, kIsWeb;
import 'package:flutter_webrtc/flutter_webrtc.dart';

import '../utils/logger.dart';

class AudioInputDevice {
  const AudioInputDevice({required this.id, required this.label});

  final String id;
  final String label;
}

class AudioDevices {
  AudioDevices._();

  static Future<List<AudioInputDevice>> microphones() async {
    try {
      final devices = await navigator.mediaDevices.enumerateDevices();
      final mics = <AudioInputDevice>[];
      final seen = <String>{};
      for (final device in devices) {
        if (device.kind != 'audioinput') continue;
        if (device.deviceId.isEmpty || !seen.add(device.deviceId)) continue;
        mics.add(
          AudioInputDevice(id: device.deviceId, label: device.label.trim()),
        );
      }
      return mics;
    } catch (e) {
      logger.w('[call] enumerateDevices: $e');
      return const [];
    }
  }

  static bool get switchesInsideEngine =>
      !kIsWeb &&
      (defaultTargetPlatform == TargetPlatform.android ||
          defaultTargetPlatform == TargetPlatform.iOS ||
          defaultTargetPlatform == TargetPlatform.macOS);

  static Future<void> selectInput(String deviceId) async {
    try {
      await Helper.selectAudioInput(deviceId);
    } catch (e) {
      logger.w('[call] selectAudioInput($deviceId): $e');
    }
  }

  static Object micConstraints(
    String? deviceId, {
    bool monitorCapture = false,
  }) {
    final constraints = <String, dynamic>{};
    final hasDevice = deviceId != null && deviceId.isNotEmpty;
    if (hasDevice && !switchesInsideEngine) {
      if (kIsWeb) {
        constraints['deviceId'] = deviceId;
      } else {
        constraints['optional'] = [
          {'sourceId': deviceId},
        ];
      }
    }
    if (monitorCapture) {
      constraints['echoCancellation'] = true;
      constraints['noiseSuppression'] = false;
      constraints['autoGainControl'] = false;
      constraints['highpassFilter'] = false;
    }
    return constraints.isEmpty ? true : constraints;
  }

  static Future<String?> findDevice(String token, {int attempts = 1}) async {
    for (var attempt = 0; attempt < attempts; attempt++) {
      for (final device in await microphones()) {
        if (device.id == token ||
            device.id.contains(token) ||
            device.label.contains(token)) {
          return device.id;
        }
      }
      if (attempt + 1 < attempts) {
        await Future<void>.delayed(const Duration(milliseconds: 250));
      }
    }
    return null;
  }
}
