import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:it0_app/l10n/app_localizations.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:xterm/xterm.dart';
import '../../../../core/config/api_endpoints.dart';
import '../../../../core/config/app_config.dart';
import '../../../../core/network/dio_client.dart';
import '../../../../core/theme/app_colors.dart';
import '../../../auth/data/providers/auth_provider.dart';

// ---------------------------------------------------------------------------
// TODO 2E – Remote Terminal page: xterm + WebSocket
// ---------------------------------------------------------------------------

/// Fetches the list of servers for the server-selector dropdown.
final _terminalServersProvider =
    FutureProvider<List<Map<String, dynamic>>>((ref) async {
  final dio = ref.watch(dioClientProvider);
  final response = await dio.get(ApiEndpoints.servers);
  final data = response.data;
  if (data is List) return data.cast<Map<String, dynamic>>();
  if (data is Map && data.containsKey('items')) {
    return (data['items'] as List).cast<Map<String, dynamic>>();
  }
  return [];
});

// ---------------------------------------------------------------------------
// Connection status enum
// ---------------------------------------------------------------------------

enum _ConnectionStatus { disconnected, connecting, connected }

// ---------------------------------------------------------------------------
// Terminal page – ConsumerStatefulWidget
// ---------------------------------------------------------------------------

class TerminalPage extends ConsumerStatefulWidget {
  const TerminalPage({super.key});

  @override
  ConsumerState<TerminalPage> createState() => _TerminalPageState();
}

class _TerminalPageState extends ConsumerState<TerminalPage> {
  late final Terminal _terminal;
  WebSocketChannel? _channel;
  StreamSubscription? _wsSubscription;
  _ConnectionStatus _status = _ConnectionStatus.disconnected;
  String? _selectedServerId;

  @override
  void initState() {
    super.initState();
    _terminal = Terminal(maxLines: 10000);
    _terminal.onOutput = _onTerminalInput;
    _terminal.write('我智能体 远程终端\r\n');
    _terminal.write('请选择服务器并点击连接。\r\n');
  }

  @override
  void dispose() {
    _disconnect();
    super.dispose();
  }

  // ---------- WebSocket lifecycle ------------------------------------------

  Future<void> _connect() async {
    if (_selectedServerId == null || _selectedServerId!.isEmpty) {
      _terminal.write('\r\n\x1B[33m[!] 请先选择服务器\x1B[0m\r\n');
      return;
    }

    setState(() => _status = _ConnectionStatus.connecting);
    _terminal.write('\r\n\x1B[33m[*] 正在连接服务器 $_selectedServerId...\x1B[0m\r\n');

    try {
      final config = ref.read(appConfigProvider);
      final storage = ref.read(secureStorageProvider);
      final token = await storage.read(key: 'access_token');

      final queryParams = <String, String>{
        'serverId': _selectedServerId!,
      };
      if (token != null) {
        queryParams['token'] = token;
      }

      final uri = Uri.parse(
        '${config.wsBaseUrl}${ApiEndpoints.wsTerminal}',
      ).replace(queryParameters: queryParams);

      _channel = WebSocketChannel.connect(uri);

      // Wait for the connection to be ready
      await _channel!.ready;

      _wsSubscription = _channel!.stream.listen(
        _onWsMessage,
        onDone: _onWsDone,
        onError: _onWsError,
      );

      if (mounted) {
        setState(() => _status = _ConnectionStatus.connected);
        _terminal.write('\x1B[32m[+] 已连接\x1B[0m\r\n');
      }
    } catch (e) {
      if (mounted) {
        setState(() => _status = _ConnectionStatus.disconnected);
        _terminal.write('\x1B[31m[-] 连接失败: $e\x1B[0m\r\n');
      }
    }
  }

  void _disconnect() {
    _wsSubscription?.cancel();
    _wsSubscription = null;
    _channel?.sink.close();
    _channel = null;
    if (mounted) {
      setState(() => _status = _ConnectionStatus.disconnected);
    }
  }

  // ---------- WebSocket message handlers -----------------------------------

  void _onWsMessage(dynamic data) {
    if (data is String) {
      // Try decoding as JSON first (server may wrap output in a message
      // envelope like {"type":"output","data":"..."}).
      try {
        final decoded = jsonDecode(data) as Map<String, dynamic>;
        final output = decoded['data'] as String? ?? decoded['output'] as String? ?? '';
        if (output.isNotEmpty) {
          _terminal.write(output);
        }
      } catch (_) {
        // Not JSON – treat as raw terminal output.
        _terminal.write(data);
      }
    }
  }

  void _onWsDone() {
    if (mounted) {
      setState(() => _status = _ConnectionStatus.disconnected);
      _terminal.write('\r\n\x1B[33m[*] 连接已关闭\x1B[0m\r\n');
    }
  }

  void _onWsError(dynamic error) {
    if (mounted) {
      setState(() => _status = _ConnectionStatus.disconnected);
      _terminal.write('\r\n\x1B[31m[-] WebSocket 错误: $error\x1B[0m\r\n');
    }
  }

  // ---------- Terminal input handler ----------------------------------------

  void _onTerminalInput(String data) {
    if (_status != _ConnectionStatus.connected || _channel == null) {
      return;
    }
    // Send raw input to the server via WebSocket.
    _channel!.sink.add(jsonEncode({'type': 'input', 'data': data}));
  }

  // ---------- UI helpers ---------------------------------------------------

  Color get _statusColor {
    switch (_status) {
      case _ConnectionStatus.connected:
        return AppColors.success;
      case _ConnectionStatus.connecting:
        return AppColors.warning;
      case _ConnectionStatus.disconnected:
        return AppColors.error;
    }
  }

  String _statusLabel(BuildContext context) {
    switch (_status) {
      case _ConnectionStatus.connected:
        return AppLocalizations.of(context).terminalConnectedLabel;
      case _ConnectionStatus.connecting:
        return AppLocalizations.of(context).terminalConnectingLabel;
      case _ConnectionStatus.disconnected:
        return AppLocalizations.of(context).terminalDisconnectedLabel;
    }
  }

  // ---------- Build --------------------------------------------------------

  @override
  Widget build(BuildContext context) {
    final serversAsync = ref.watch(_terminalServersProvider);

    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalizations.of(context).terminalTitle),
        actions: [
          // Connection status indicator
          Padding(
            padding: const EdgeInsets.only(right: 8),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                Container(
                  width: 10,
                  height: 10,
                  decoration: BoxDecoration(
                    color: _statusColor,
                    shape: BoxShape.circle,
                  ),
                ),
                const SizedBox(width: 6),
                Text(
                  _statusLabel(context),
                  style: TextStyle(
                    color: _statusColor,
                    fontSize: 12,
                    fontWeight: FontWeight.w500,
                  ),
                ),
              ],
            ),
          ),
          // Reconnect / Disconnect button
          if (_status == _ConnectionStatus.disconnected)
            IconButton(
              icon: const Icon(Icons.refresh),
              tooltip: '重新连接',
              onPressed: _selectedServerId != null ? _connect : null,
            )
          else if (_status == _ConnectionStatus.connected)
            IconButton(
              icon: const Icon(Icons.link_off),
              tooltip: '断开连接',
              onPressed: () {
                _disconnect();
                _terminal.write('\r\n\x1B[33m[*] 已断开连接\x1B[0m\r\n');
              },
            ),
        ],
      ),
      body: Column(
        children: [
          // ---- Server selector bar ----------------------------------------
          Container(
            color: AppColors.surface,
            padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
            child: Row(
              children: [
                const Icon(Icons.dns, size: 20, color: AppColors.textSecondary),
                const SizedBox(width: 8),
                Expanded(
                  child: serversAsync.when(
                    data: (servers) {
                      if (servers.isEmpty) {
                        return Text(
                          AppLocalizations.of(context).terminalNoAvailableServers,
                          style: const TextStyle(
                            color: AppColors.textMuted,
                            fontSize: 14,
                          ),
                        );
                      }
                      return DropdownButtonHideUnderline(
                        child: DropdownButton<String>(
                          value: _selectedServerId,
                          hint: Text(
                            AppLocalizations.of(context).terminalSelectServerHint,
                            style: const TextStyle(
                              color: AppColors.textMuted,
                              fontSize: 14,
                            ),
                          ),
                          isExpanded: true,
                          dropdownColor: AppColors.surface,
                          style: const TextStyle(
                            color: AppColors.textPrimary,
                            fontSize: 14,
                          ),
                          items: servers.map((s) {
                            final id = s['id']?.toString() ?? '';
                            final hostname =
                                s['hostname'] as String? ?? s['name'] as String? ?? id;
                            final ip = s['ip'] as String? ?? s['address'] as String? ?? '';
                            return DropdownMenuItem(
                              value: id,
                              child: Text(
                                ip.isNotEmpty ? '$hostname ($ip)' : hostname,
                                overflow: TextOverflow.ellipsis,
                              ),
                            );
                          }).toList(),
                          onChanged: _status == _ConnectionStatus.connected
                              ? null
                              : (value) {
                                  setState(() => _selectedServerId = value);
                                },
                        ),
                      );
                    },
                    loading: () => const SizedBox(
                      height: 20,
                      child: LinearProgressIndicator(),
                    ),
                    error: (e, _) => Row(
                      children: [
                        const Icon(Icons.error_outline,
                            size: 16, color: AppColors.error),
                        const SizedBox(width: 6),
                        Expanded(
                          child: Text(
                            AppLocalizations.of(context).terminalLoadServersError,
                            style: const TextStyle(
                              color: AppColors.error,
                              fontSize: 13,
                            ),
                          ),
                        ),
                        IconButton(
                          icon: const Icon(Icons.refresh, size: 18),
                          onPressed: () =>
                              ref.invalidate(_terminalServersProvider),
                        ),
                      ],
                    ),
                  ),
                ),
                const SizedBox(width: 8),
                // Connect button
                SizedBox(
                  height: 36,
                  child: FilledButton.icon(
                    onPressed: _status == _ConnectionStatus.connecting
                        ? null
                        : _status == _ConnectionStatus.connected
                            ? () {
                                _disconnect();
                                _terminal.write(
                                    '\r\n\x1B[33m[*] 已断开连接\x1B[0m\r\n');
                              }
                            : _connect,
                    icon: Icon(
                      _status == _ConnectionStatus.connected
                          ? Icons.link_off
                          : Icons.play_arrow,
                      size: 18,
                    ),
                    label: Text(
                      _status == _ConnectionStatus.connected
                          ? AppLocalizations.of(context).terminalDisconnectButton
                          : _status == _ConnectionStatus.connecting
                              ? AppLocalizations.of(context).terminalConnectingMessage
                              : AppLocalizations.of(context).terminalConnectButton,
                      style: const TextStyle(fontSize: 13),
                    ),
                  ),
                ),
              ],
            ),
          ),

          // ---- xterm terminal view ----------------------------------------
          Expanded(
            child: Container(
              color: Colors.black,
              child: TerminalView(
                _terminal,
                textStyle: const TerminalStyle(
                  fontSize: 14,
                  fontFamily: 'monospace',
                ),
                padding: const EdgeInsets.all(4),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
