import 'package:flutter/material.dart';

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

/// Loads available input/output audio devices.
typedef AudioDeviceListLoader = Future<rust.BridgeAudioDeviceList> Function();

/// Persists a selected audio device id.
typedef AudioDeviceSetter = Future<void> Function({String? id});

/// Which desktop audio device group this tile manages.
enum AudioDeviceKind {
  /// Capture device.
  input,

  /// Playback device.
  output,
}

/// Desktop audio device selector tile.
class AudioDeviceListTile extends StatefulWidget {
  /// Construct an audio device list tile.
  const AudioDeviceListTile({
    super.key,
    required this.label,
    required this.kind,
    AudioDeviceListLoader? loadDevices,
    AudioDeviceSetter? setInputDevice,
    AudioDeviceSetter? setOutputDevice,
  }) : loadDevices = loadDevices ?? rust.listAudioDevices,
       setInputDevice = setInputDevice ?? rust.setInputDevice,
       setOutputDevice = setOutputDevice ?? rust.setOutputDevice;

  /// Tile title.
  final String label;

  /// Device group managed by this tile.
  final AudioDeviceKind kind;

  /// Loads available devices.
  final AudioDeviceListLoader loadDevices;

  /// Selects an input device.
  final AudioDeviceSetter setInputDevice;

  /// Selects an output device.
  final AudioDeviceSetter setOutputDevice;

  @override
  State<AudioDeviceListTile> createState() => _AudioDeviceListTileState();
}

class _AudioDeviceListTileState extends State<AudioDeviceListTile> {
  List<rust.BridgeAudioDevice> _devices = [];
  String? _selectedDeviceId;
  bool _loaded = false;

  @override
  void initState() {
    super.initState();
    _loadDevices();
  }

  Future<void> _loadDevices() async {
    final list = await widget.loadDevices();
    if (!mounted) return;
    setState(() {
      _devices = switch (widget.kind) {
        AudioDeviceKind.input => list.inputDevices,
        AudioDeviceKind.output => list.outputDevices,
      };
      _selectedDeviceId = _devices
          .where((device) => device.isSelected)
          .firstOrNull
          ?.id;
      _loaded = true;
    });
  }

  Future<void> _selectDevice(String? deviceId) async {
    switch (widget.kind) {
      case AudioDeviceKind.input:
        await widget.setInputDevice(id: deviceId);
      case AudioDeviceKind.output:
        await widget.setOutputDevice(id: deviceId);
    }
    if (!mounted) return;
    setState(() {
      _selectedDeviceId = deviceId;
    });

    final selectedName = _selectedDevice?.name ?? 'System default';
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('${widget.label} set to $selectedName'),
        duration: const Duration(seconds: 2),
      ),
    );
  }

  rust.BridgeAudioDevice? get _selectedDevice {
    if (_selectedDeviceId == null) {
      return null;
    }
    for (final device in _devices) {
      if (device.id == _selectedDeviceId) {
        return device;
      }
    }
    return null;
  }

  @override
  Widget build(BuildContext context) {
    final selectedDevice = _selectedDevice;
    final subtitleText = selectedDevice?.name ?? 'System default';
    final leadingIcon = switch (widget.kind) {
      AudioDeviceKind.input => Icons.mic_none,
      AudioDeviceKind.output => Icons.headphones,
    };

    if (!_loaded) {
      return ListTile(
        title: Text(widget.label),
        subtitle: const Text('Loading...'),
        trailing: const SizedBox(
          width: 16,
          height: 16,
          child: CircularProgressIndicator(strokeWidth: 2),
        ),
      );
    }
    if (_devices.isEmpty) {
      return ListTile(
        title: Text(widget.label),
        subtitle: const Text('System default'),
        leading: const Icon(Icons.check_circle_outline, size: 18),
      );
    }
    return ExpansionTile(
      title: Text(widget.label),
      subtitle: Text(subtitleText),
      leading: Icon(leadingIcon, size: 18),
      children: [
        ListTile(
          dense: true,
          title: const Text('System default', style: TextStyle(fontSize: 13)),
          subtitle: const Text('Use the OS default device'),
          trailing: _selectedDeviceId == null
              ? const Icon(Icons.check, size: 16, color: Colors.green)
              : null,
          onTap: _selectedDeviceId == null ? null : () => _selectDevice(null),
        ),
        for (final device in _devices)
          ListTile(
            dense: true,
            title: Text(device.name, style: const TextStyle(fontSize: 13)),
            subtitle: device.details.isEmpty ? null : Text(device.details),
            trailing: device.id == _selectedDeviceId
                ? const Icon(Icons.check, size: 16, color: Colors.green)
                : device.isDefault
                ? const Icon(Icons.radio_button_checked, size: 16)
                : null,
            onTap: device.id == _selectedDeviceId
                ? null
                : () => _selectDevice(device.id),
          ),
      ],
    );
  }
}
