import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(const WirelessTextSyncerApp());
}

class WirelessTextSyncerApp extends StatelessWidget {
  const WirelessTextSyncerApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'WirelessTextSyncer',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF2563EB)),
        scaffoldBackgroundColor: const Color(0xFFF8FAFC),
        useMaterial3: true,
      ),
      home: const InputSyncPage(),
    );
  }
}

enum SendButtonState { idle, sending, success }

const connectionInfoFontFamily = 'WDXL Lubrifont SC';

class ConnectionSnapshot {
  const ConnectionSnapshot({
    this.connected = false,
    this.connecting = false,
    this.host = '',
    this.port = 8181,
    this.name = '',
    this.lastError,
  });

  factory ConnectionSnapshot.fromMap(Map<dynamic, dynamic>? map) {
    if (map == null) {
      return const ConnectionSnapshot();
    }

    return ConnectionSnapshot(
      connected: map['connected'] == true,
      connecting: map['connecting'] == true,
      host: (map['host'] as String?) ?? '',
      port: (map['port'] as num?)?.toInt() ?? 8181,
      name: (map['name'] as String?) ?? '',
      lastError: map['lastError'] as String?,
    );
  }

  final bool connected;
  final bool connecting;
  final String host;
  final int port;
  final String name;
  final String? lastError;
}

class DiscoveredDevice {
  const DiscoveredDevice({
    required this.name,
    required this.host,
    required this.port,
  });

  factory DiscoveredDevice.fromMap(Map<dynamic, dynamic> map) {
    return DiscoveredDevice(
      name: (map['name'] as String?) ?? 'Windows 桌面端',
      host: (map['host'] as String?) ?? '',
      port: (map['port'] as num?)?.toInt() ?? 8181,
    );
  }

  final String name;
  final String host;
  final int port;

  String get endpoint => '$host:$port';
}

class NativeConnectionApi {
  static const MethodChannel _methodChannel = MethodChannel(
    'wireless_text_syncer/connection',
  );
  static const EventChannel _eventChannel = EventChannel(
    'wireless_text_syncer/connection_state',
  );

  Stream<ConnectionSnapshot> watchState() {
    return _eventChannel.receiveBroadcastStream().map((event) {
      return ConnectionSnapshot.fromMap(event as Map<dynamic, dynamic>?);
    });
  }

  Future<ConnectionSnapshot> getState() async {
    try {
      final state = await _methodChannel.invokeMapMethod<dynamic, dynamic>(
        'getState',
      );
      return ConnectionSnapshot.fromMap(state);
    } on MissingPluginException {
      return const ConnectionSnapshot();
    }
  }

  Future<void> connect(String host, int port, {String? name}) async {
    await _methodChannel.invokeMethod<void>('connect', {
      'host': host,
      'port': port,
      if (name != null) 'name': name,
    });
  }

  Future<void> disconnect() async {
    await _methodChannel.invokeMethod<void>('disconnect');
  }

  Future<bool> sendText(String text) async {
    final result = await _methodChannel.invokeMethod<bool>('sendText', {
      'text': text,
    });
    return result ?? false;
  }

  Future<bool> sendEnter() async {
    final result = await _methodChannel.invokeMethod<bool>('sendEnter');
    return result ?? false;
  }

  Future<bool> sendMute(bool muted) async {
    final result = await _methodChannel.invokeMethod<bool>('sendMute', {
      'muted': muted,
    });
    return result ?? false;
  }

  Future<List<DiscoveredDevice>> startDiscovery() async {
    try {
      final result = await _methodChannel.invokeListMethod<dynamic>(
        'startDiscovery',
      );
      return (result ?? const [])
          .whereType<Map<dynamic, dynamic>>()
          .map(DiscoveredDevice.fromMap)
          .where((device) => device.host.isNotEmpty)
          .toList();
    } on MissingPluginException {
      return const [];
    }
  }
}

class InputSyncPage extends StatefulWidget {
  const InputSyncPage({super.key});

  @override
  State<InputSyncPage> createState() => _InputSyncPageState();
}

class _InputSyncPageState extends State<InputSyncPage>
    with TickerProviderStateMixin, WidgetsBindingObserver {
  static const _hostKey = 'server_host';
  static const _portKey = 'server_port';
  static const _historyKey = 'send_history';
  static const _clearAfterSendKey = 'clear_after_send';
  static const _appendEnterKey = 'append_enter';
  static const _maxHistoryItems = 10;

  final api = NativeConnectionApi();
  final hostController = TextEditingController();
  final portController = TextEditingController(text: '8181');
  final inputController = TextEditingController();
  final inputFocusNode = FocusNode();

  late final AnimationController statusPulseController;
  late final AnimationController radarPulseController;
  StreamSubscription<ConnectionSnapshot>? stateSubscription;
  List<String> sendHistory = [];
  List<DiscoveredDevice> discoveredDevices = [];
  SendButtonState sendButtonState = SendButtonState.idle;
  ConnectionSnapshot connection = const ConnectionSnapshot();
  bool appendEnter = false;
  bool clearAfterSend = false;
  bool headerExpanded = true;
  bool inputFocused = false;
  bool scanning = false;
  bool desktopMuted = false;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    statusPulseController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1300),
      lowerBound: 0.55,
      upperBound: 1,
    )..repeat(reverse: true);
    radarPulseController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1500),
    )..repeat();
    inputController.addListener(_handleDraftChanged);
    inputFocusNode.addListener(_handleFocusChanged);
    _loadSavedState();
    _subscribeConnectionState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    stateSubscription?.cancel();
    statusPulseController.dispose();
    radarPulseController.dispose();
    hostController.dispose();
    portController.dispose();
    inputController.dispose();
    inputFocusNode.dispose();
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      unawaited(_syncSharedPrefsFromDisk());
    }
  }

  Future<void> _loadSavedState() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.reload();
    final nativeState = await api.getState();
    if (!mounted) {
      return;
    }

    setState(() {
      hostController.text = prefs.getString(_hostKey) ?? nativeState.host;
      portController.text =
          prefs.getString(_portKey) ?? nativeState.port.toString();
      clearAfterSend = prefs.getBool(_clearAfterSendKey) ?? false;
      appendEnter = prefs.getBool(_appendEnterKey) ?? false;
      sendHistory = _readHistory(prefs);
      connection = nativeState;
      headerExpanded = !nativeState.connected;
    });

    if (!nativeState.connected) {
      unawaited(_scanForDevices());
    }
  }

  void _subscribeConnectionState() {
    stateSubscription = api.watchState().listen((nextState) {
      if (!mounted) {
        return;
      }
      setState(() {
        connection = nextState;
        if (nextState.connected) {
          headerExpanded = false;
          hostController.text = nextState.host;
          portController.text = nextState.port.toString();
        } else if (!nextState.connecting) {
          headerExpanded = true;
        }
        if (!nextState.connected) {
          sendButtonState = SendButtonState.idle;
          desktopMuted = false;
        }
      });

      if (nextState.connected) {
        inputFocusNode.requestFocus();
      } else if (nextState.lastError != null) {
        _showToast(nextState.lastError!);
      }
    }, onError: (_) {});
  }

  void _handleDraftChanged() {
    setState(() {});
  }

  void _handleFocusChanged() {
    setState(() {
      inputFocused = inputFocusNode.hasFocus;
    });
  }

  Future<void> _scanForDevices() async {
    if (scanning) {
      return;
    }

    setState(() {
      scanning = true;
    });

    final devices = await api.startDiscovery();
    if (!mounted) {
      return;
    }

    setState(() {
      scanning = false;
      discoveredDevices = devices;
    });

    if (devices.length == 1 &&
        !connection.connected &&
        !connection.connecting) {
      await _connectDevice(devices.single);
    }
  }

  Future<void> _connect({String? name}) async {
    final host = hostController.text.trim();
    final portText = portController.text.trim();
    final port = int.tryParse(portText);
    if (host.isEmpty || port == null) {
      _showToast('请先填写 Windows IP 和端口');
      setState(() {
        headerExpanded = true;
      });
      return;
    }

    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_hostKey, host);
    await prefs.setString(_portKey, port.toString());

    setState(() {
      connection = ConnectionSnapshot(
        connecting: true,
        host: host,
        port: port,
        name: name ?? '',
      );
    });

    try {
      await api.connect(host, port, name: name);
    } on PlatformException catch (exception) {
      _showToast(exception.message ?? '连接失败，请检查地址');
      setState(() {
        connection = ConnectionSnapshot(
          host: host,
          port: port,
          name: name ?? '',
        );
        headerExpanded = true;
      });
    }
  }

  Future<void> _connectDevice(DiscoveredDevice device) async {
    hostController.text = device.host;
    portController.text = device.port.toString();
    await _connect(name: device.name);
  }

  Future<void> _disconnect() async {
    await api.disconnect();
    setState(() {
      connection = ConnectionSnapshot(
        host: hostController.text.trim(),
        port: int.tryParse(portController.text.trim()) ?? 8181,
        name: connection.name,
      );
      headerExpanded = true;
      sendButtonState = SendButtonState.idle;
    });
    _showToast('已断开连接');
  }

  Future<void> _sendCurrentText() async {
    if (!_canSend) {
      return;
    }

    final draft = inputController.text;
    setState(() {
      sendButtonState = SendButtonState.sending;
    });

    try {
      final sent = await api.sendText(draft);
      final enterSent = !sent || !appendEnter ? true : await api.sendEnter();
      if (!sent || !enterSent) {
        _showToast('发送失败，连接已断开');
        setState(() {
          sendButtonState = SendButtonState.idle;
          headerExpanded = true;
        });
        return;
      }

      await _saveHistory(draft);

      if (clearAfterSend) {
        inputController.clear();
      }

      if (!mounted) {
        return;
      }

      setState(() {
        sendButtonState = SendButtonState.success;
      });
      await Future<void>.delayed(const Duration(milliseconds: 1500));
      if (mounted) {
        setState(() {
          sendButtonState = SendButtonState.idle;
        });
        inputFocusNode.requestFocus();
      }
    } on PlatformException {
      _showToast('发送失败，连接已断开');
      setState(() {
        sendButtonState = SendButtonState.idle;
        headerExpanded = true;
      });
    }
  }

  Future<void> _toggleMute() async {
    if (!connection.connected) {
      return;
    }
    final nextMuted = !desktopMuted;
    setState(() {
      desktopMuted = nextMuted;
    });
    final sent = await api.sendMute(nextMuted);
    if (!sent && mounted) {
      setState(() {
        desktopMuted = !nextMuted;
      });
      _showToast('发送失败，连接已断开');
    }
  }

  Future<void> _saveHistory(String text) async {
    final trimmed = text.trim();
    if (trimmed.isEmpty) {
      return;
    }

    final nextHistory = [
      text,
      ...sendHistory.where((item) => item != text),
    ].take(_maxHistoryItems).toList();
    final prefs = await SharedPreferences.getInstance();
    await prefs.setStringList(_historyKey, nextHistory);

    if (mounted) {
      setState(() {
        sendHistory = nextHistory;
      });
    }
  }

  Future<void> _setClearAfterSend(bool value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(_clearAfterSendKey, value);
    setState(() {
      clearAfterSend = value;
    });
  }

  Future<void> _setAppendEnter(bool value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(_appendEnterKey, value);
    setState(() {
      appendEnter = value;
    });
  }

  Future<void> _syncSharedPrefsFromDisk() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.reload();
    final nextAppendEnter = prefs.getBool(_appendEnterKey) ?? false;
    final nextHistory = _readHistory(prefs);
    if (!mounted) {
      return;
    }

    if (nextAppendEnter != appendEnter ||
        !_stringListsEqual(nextHistory, sendHistory)) {
      setState(() {
        appendEnter = nextAppendEnter;
        sendHistory = nextHistory;
      });
    }
  }

  bool _stringListsEqual(List<String> left, List<String> right) {
    if (left.length != right.length) {
      return false;
    }

    for (var index = 0; index < left.length; index += 1) {
      if (left[index] != right[index]) {
        return false;
      }
    }

    return true;
  }

  List<String> _readHistory(SharedPreferences prefs) {
    try {
      return prefs.getStringList(_historyKey) ?? [];
    } catch (_) {
      return [];
    }
  }

  void _restoreHistory(String text) {
    inputController.text = text;
    inputController.selection = TextSelection.collapsed(offset: text.length);
    Navigator.of(context).pop();
    inputFocusNode.requestFocus();
  }

  void _showHistorySheet() {
    showModalBottomSheet<void>(
      context: context,
      showDragHandle: true,
      isScrollControlled: true,
      backgroundColor: Theme.of(context).colorScheme.surface,
      builder: (context) {
        return SafeArea(
          child: SizedBox(
            height: MediaQuery.of(context).size.height * 0.58,
            child: Column(
              children: [
                Padding(
                  padding: const EdgeInsets.fromLTRB(20, 0, 12, 10),
                  child: Row(
                    children: [
                      const Expanded(
                        child: Text(
                          '发送历史',
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.w700,
                          ),
                        ),
                      ),
                      IconButton(
                        tooltip: '关闭',
                        onPressed: () => Navigator.of(context).pop(),
                        icon: const Icon(Icons.close),
                      ),
                    ],
                  ),
                ),
                Expanded(
                  child: sendHistory.isEmpty
                      ? const _HistoryEmptyState()
                      : ListView.separated(
                          padding: const EdgeInsets.fromLTRB(16, 0, 16, 20),
                          itemBuilder: (context, index) {
                            final item = sendHistory[index];
                            return ListTile(
                              minVerticalPadding: 12,
                              shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(8),
                              ),
                              tileColor: const Color(0xFFF8FAFC),
                              title: Text(
                                item,
                                maxLines: 3,
                                overflow: TextOverflow.ellipsis,
                              ),
                              subtitle: Text('${item.length} 字符'),
                              onTap: () => _restoreHistory(item),
                            );
                          },
                          separatorBuilder: (_, _) => const SizedBox(height: 8),
                          itemCount: sendHistory.length,
                        ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  void _showToast(String message) {
    if (!mounted) {
      return;
    }

    ScaffoldMessenger.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(
        SnackBar(
          behavior: SnackBarBehavior.floating,
          content: Text(message),
          duration: const Duration(milliseconds: 1600),
        ),
      );
  }

  bool get _canSend {
    return connection.connected &&
        inputController.text.isNotEmpty &&
        sendButtonState != SendButtonState.sending;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: true,
      body: SafeArea(
        child: Column(
          children: [
            _buildHeader(context),
            Expanded(child: _buildDraftBoard(context)),
            _buildFooter(context),
          ],
        ),
      ),
    );
  }

  Widget _buildHeader(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return Material(
      color: colorScheme.surface,
      elevation: 1,
      child: AnimatedSize(
        duration: const Duration(milliseconds: 260),
        curve: Curves.easeOutCubic,
        child: Padding(
          padding: const EdgeInsets.fromLTRB(12, 8, 12, 10),
          child: Column(
            children: [
              InkWell(
                borderRadius: BorderRadius.circular(8),
                onTap: () {
                  setState(() {
                    headerExpanded = !headerExpanded;
                  });
                },
                child: SizedBox(
                  height: 52,
                  child: Row(
                    children: [
                      Expanded(
                        child: _ConnectionSummary(
                          connected: connection.connected,
                          connecting: connection.connecting,
                          endpoint: connection.host.isEmpty
                              ? '未设置地址'
                              : '${connection.host}:${connection.port}',
                          deviceName: connection.name.isEmpty
                              ? 'Windows 桌面端'
                              : connection.name,
                          animation: statusPulseController,
                        ),
                      ),
                      const SizedBox(width: 8),
                      Icon(
                        headerExpanded
                            ? Icons.keyboard_arrow_up
                            : Icons.keyboard_arrow_down,
                      ),
                    ],
                  ),
                ),
              ),
              AnimatedCrossFade(
                firstChild: const SizedBox.shrink(),
                secondChild: Padding(
                  padding: const EdgeInsets.only(top: 8),
                  child: Column(
                    children: [
                      Row(
                        children: [
                          Expanded(
                            flex: 7,
                            child: TextField(
                              controller: hostController,
                              decoration: const InputDecoration(
                                labelText: 'IP 地址',
                                border: OutlineInputBorder(),
                                isDense: true,
                              ),
                              keyboardType: TextInputType.url,
                            ),
                          ),
                          const SizedBox(width: 8),
                          Expanded(
                            flex: 3,
                            child: TextField(
                              controller: portController,
                              decoration: const InputDecoration(
                                labelText: '端口',
                                border: OutlineInputBorder(),
                                isDense: true,
                              ),
                              keyboardType: TextInputType.number,
                            ),
                          ),
                          const SizedBox(width: 8),
                          IconButton.filledTonal(
                            tooltip: connection.connected ? '断开连接' : '连接',
                            style: IconButton.styleFrom(
                              minimumSize: const Size(48, 48),
                              foregroundColor: connection.connected
                                  ? colorScheme.error
                                  : colorScheme.primary,
                            ),
                            onPressed: connection.connecting
                                ? null
                                : connection.connected
                                ? _disconnect
                                : _connect,
                            icon: Icon(
                              connection.connected
                                  ? Icons.link_off
                                  : Icons.link,
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 12),
                      _buildRadar(context),
                    ],
                  ),
                ),
                crossFadeState: headerExpanded
                    ? CrossFadeState.showSecond
                    : CrossFadeState.showFirst,
                duration: const Duration(milliseconds: 260),
                sizeCurve: Curves.easeOutCubic,
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildRadar(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            AnimatedBuilder(
              animation: radarPulseController,
              builder: (context, child) {
                final scale = scanning
                    ? 0.85 + radarPulseController.value * 0.3
                    : 1.0;
                return Transform.scale(
                  scale: scale,
                  child: Icon(
                    Icons.radar,
                    color: scanning
                        ? colorScheme.primary
                        : colorScheme.onSurfaceVariant,
                  ),
                );
              },
            ),
            const SizedBox(width: 8),
            Expanded(
              child: Text(
                '局域网设备雷达',
                style: TextStyle(
                  color: colorScheme.onSurfaceVariant,
                  fontWeight: FontWeight.w700,
                ),
              ),
            ),
            TextButton.icon(
              onPressed: scanning ? null : _scanForDevices,
              icon: scanning
                  ? const SizedBox(
                      width: 16,
                      height: 16,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Icon(Icons.refresh),
              label: Text(scanning ? '扫描中' : '刷新'),
            ),
          ],
        ),
        const SizedBox(height: 8),
        if (discoveredDevices.isEmpty)
          Container(
            width: double.infinity,
            padding: const EdgeInsets.all(12),
            decoration: BoxDecoration(
              color: const Color(0xFFF8FAFC),
              borderRadius: BorderRadius.circular(8),
              border: Border.all(color: const Color(0xFFE2E8F0)),
            ),
            child: Text(
              scanning ? '正在寻找附近的 Windows 桌面端...' : '暂无发现，可刷新或使用上方 IP 手动连接',
              style: TextStyle(color: colorScheme.onSurfaceVariant),
            ),
          )
        else
          ...discoveredDevices.map((device) {
            return Padding(
              padding: const EdgeInsets.only(bottom: 8),
              child: InkWell(
                borderRadius: BorderRadius.circular(8),
                onTap: connection.connecting
                    ? null
                    : () => _connectDevice(device),
                child: Container(
                  padding: const EdgeInsets.all(12),
                  decoration: BoxDecoration(
                    color: colorScheme.surface,
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(color: const Color(0xFFE2E8F0)),
                  ),
                  child: Row(
                    children: [
                      const Icon(Icons.desktop_windows_outlined),
                      const SizedBox(width: 10),
                      Expanded(
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              device.name,
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style: const TextStyle(
                                fontWeight: FontWeight.w700,
                              ),
                            ),
                            Text(
                              device.endpoint,
                              style: TextStyle(
                                color: colorScheme.onSurfaceVariant,
                                fontSize: 12,
                              ),
                            ),
                          ],
                        ),
                      ),
                      Container(
                        padding: const EdgeInsets.symmetric(
                          horizontal: 8,
                          vertical: 4,
                        ),
                        decoration: BoxDecoration(
                          color: const Color(0xFFDCFCE7),
                          borderRadius: BorderRadius.circular(999),
                        ),
                        child: const Text(
                          '可连接',
                          style: TextStyle(
                            color: Color(0xFF166534),
                            fontSize: 12,
                            fontWeight: FontWeight.w700,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            );
          }),
      ],
    );
  }

  Widget _buildDraftBoard(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxHeight < 72) {
          return const SizedBox.shrink();
        }

        return Padding(
          padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
          child: Column(
            children: [
              SizedBox(
                height: 44,
                child: Row(
                  children: [
                    Text(
                      '草稿板',
                      style: TextStyle(
                        color: colorScheme.onSurfaceVariant,
                        fontWeight: FontWeight.w600,
                      ),
                    ),
                    const Spacer(),
                    IconButton(
                      tooltip: '历史记录',
                      onPressed: _showHistorySheet,
                      icon: const Icon(Icons.history),
                    ),
                    AnimatedSwitcher(
                      duration: const Duration(milliseconds: 180),
                      child: inputController.text.isEmpty
                          ? const SizedBox(width: 48, height: 48)
                          : IconButton(
                              key: const ValueKey('clear-draft'),
                              tooltip: '清空',
                              onPressed: inputController.clear,
                              icon: const Icon(Icons.delete_outline),
                            ),
                    ),
                    IconButton(
                      tooltip: desktopMuted ? '取消静音' : '静音桌面',
                      onPressed: connection.connected ? _toggleMute : null,
                      icon: Icon(
                        desktopMuted ? Icons.volume_off : Icons.volume_up,
                      ),
                    ),
                  ],
                ),
              ),
              Expanded(
                child: AnimatedContainer(
                  duration: const Duration(milliseconds: 180),
                  curve: Curves.easeOut,
                  decoration: BoxDecoration(
                    color: colorScheme.surface,
                    borderRadius: BorderRadius.circular(8),
                    border: Border.all(
                      color: inputFocused
                          ? colorScheme.primary
                          : const Color(0xFFE2E8F0),
                      width: inputFocused ? 2 : 1,
                    ),
                  ),
                  child: Stack(
                    children: [
                      TextField(
                        controller: inputController,
                        focusNode: inputFocusNode,
                        autofocus: true,
                        expands: true,
                        maxLines: null,
                        minLines: null,
                        textAlignVertical: TextAlignVertical.top,
                        decoration: const InputDecoration(
                          border: InputBorder.none,
                          contentPadding: EdgeInsets.fromLTRB(16, 16, 16, 42),
                          hintText: '点击输入或语音录入... 发送后草稿会保留，方便随时修改',
                        ),
                        keyboardType: TextInputType.multiline,
                      ),
                      Positioned(
                        right: 14,
                        bottom: 10,
                        child: Text(
                          '${inputController.text.length} 字符',
                          style: TextStyle(
                            color: colorScheme.onSurfaceVariant.withValues(
                              alpha: 0.72,
                            ),
                            fontSize: 12,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        );
      },
    );
  }

  Widget _buildFooter(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return Material(
      color: colorScheme.surface,
      elevation: 4,
      child: Padding(
        padding: const EdgeInsets.fromLTRB(12, 10, 12, 12),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Row(
              children: [
                Expanded(
                  child: _FooterToggle(
                    label: '发送后清空',
                    value: clearAfterSend,
                    onChanged: _setClearAfterSend,
                  ),
                ),
                const SizedBox(width: 8),
                Expanded(
                  child: _FooterToggle(
                    label: '追加回车',
                    value: appendEnter,
                    onChanged: _setAppendEnter,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 10),
            SizedBox(
              width: double.infinity,
              height: 52,
              child: FilledButton.icon(
                onPressed: _canSend ? _sendCurrentText : null,
                style: FilledButton.styleFrom(
                  backgroundColor: sendButtonState == SendButtonState.success
                      ? const Color(0xFF16A34A)
                      : null,
                  disabledBackgroundColor: const Color(0xFFE2E8F0),
                  disabledForegroundColor: const Color(0xFF64748B),
                ),
                icon: _buildSendButtonIcon(),
                label: Text(
                  _sendButtonText,
                  style: const TextStyle(fontWeight: FontWeight.w700),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSendButtonIcon() {
    return switch (sendButtonState) {
      SendButtonState.sending => const SizedBox(
        width: 18,
        height: 18,
        child: CircularProgressIndicator(strokeWidth: 2),
      ),
      SendButtonState.success => const Icon(Icons.check),
      SendButtonState.idle => const Icon(Icons.send),
    };
  }

  String get _sendButtonText {
    return switch (sendButtonState) {
      SendButtonState.sending => '发送中...',
      SendButtonState.success => '发送成功',
      SendButtonState.idle => '发送到电脑',
    };
  }
}

class _ConnectionSummary extends StatelessWidget {
  const _ConnectionSummary({
    required this.connected,
    required this.connecting,
    required this.endpoint,
    required this.deviceName,
    required this.animation,
  });

  final bool connected;
  final bool connecting;
  final String endpoint;
  final String deviceName;
  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;
    final iconColor = connected
        ? const Color(0xFF16A34A)
        : connecting
        ? colorScheme.primary
        : colorScheme.error;
    final primaryTextColor = connected
        ? const Color(0xFF166534)
        : const Color(0xFF0F172A);
    final secondaryTextColor = connected
        ? const Color(0xFF15803D)
        : colorScheme.onSurfaceVariant;

    return Row(
      children: [
        AnimatedBuilder(
          animation: animation,
          builder: (context, child) {
            return Transform.scale(
              scale: connecting ? animation.value : 1,
              child: Container(
                width: 42,
                height: 42,
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  color: iconColor.withValues(alpha: 0.12),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Icon(
                  connected
                      ? Icons.sync
                      : connecting
                      ? Icons.sync
                      : Icons.sync_disabled,
                  color: iconColor,
                  size: 24,
                ),
              ),
            );
          },
        ),
        const SizedBox(width: 10),
        Expanded(
          child: SizedBox(
            height: 64,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  endpoint,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(
                    color: primaryTextColor,
                    fontFamily: connectionInfoFontFamily,
                    fontSize: 21,
                    fontWeight: FontWeight.w700,
                    height: 1.15,
                  ),
                ),
                const SizedBox(height: 3),
                Text(
                  deviceName,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(
                    color: secondaryTextColor,
                    fontFamily: connectionInfoFontFamily,
                    fontSize: 18,
                    height: 1.15,
                  ),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

class _ConnectionIndicator extends StatelessWidget {
  const _ConnectionIndicator({
    required this.connected,
    required this.connecting,
    required this.animation,
  });

  final bool connected;
  final bool connecting;
  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
    final color = connected
        ? const Color(0xFF16A34A)
        : connecting
        ? Theme.of(context).colorScheme.primary
        : const Color(0xFFDC2626);

    return AnimatedBuilder(
      animation: animation,
      builder: (context, child) {
        return _StatusDot(
          color: color,
          scale: connected || connecting ? animation.value : 1,
        );
      },
    );
  }
}

class _StatusDot extends StatelessWidget {
  const _StatusDot({required this.color, required this.scale});

  final Color color;
  final double scale;

  @override
  Widget build(BuildContext context) {
    return Transform.scale(
      scale: scale,
      child: Container(
        width: 12,
        height: 12,
        decoration: BoxDecoration(
          color: color,
          shape: BoxShape.circle,
          boxShadow: [
            BoxShadow(
              color: color.withValues(alpha: 0.24),
              blurRadius: 8,
              spreadRadius: 2,
            ),
          ],
        ),
      ),
    );
  }
}

class _FooterToggle extends StatelessWidget {
  const _FooterToggle({
    required this.label,
    required this.value,
    required this.onChanged,
  });

  final String label;
  final bool value;
  final ValueChanged<bool> onChanged;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      borderRadius: BorderRadius.circular(8),
      onTap: () => onChanged(!value),
      child: Container(
        constraints: const BoxConstraints(minHeight: 44),
        padding: const EdgeInsets.only(left: 10),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(8),
          border: Border.all(color: const Color(0xFFE2E8F0)),
        ),
        child: Row(
          children: [
            Expanded(
              child: Text(
                label,
                overflow: TextOverflow.ellipsis,
                style: const TextStyle(fontWeight: FontWeight.w600),
              ),
            ),
            Switch.adaptive(value: value, onChanged: onChanged),
          ],
        ),
      ),
    );
  }
}

class _HistoryEmptyState extends StatelessWidget {
  const _HistoryEmptyState();

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(
            Icons.history_toggle_off,
            size: 56,
            color: colorScheme.onSurfaceVariant.withValues(alpha: 0.45),
          ),
          const SizedBox(height: 12),
          Text('暂无发送记录', style: TextStyle(color: colorScheme.onSurfaceVariant)),
        ],
      ),
    );
  }
}
