import 'dart:async';
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

import '../avatar_bridge.dart';
import 'chat_message.dart';
import 'secrets.dart';
import 'speech_engine_plugin.dart';

enum VoiceChatState { idle, listening, thinking, speaking, error }

/// 把火山实时语音 SDK 的事件流编排成 avatar 状态机 +
/// 把消息流转交给 UI。
///
/// 按住说话生命周期：
///   按下:
///     - 若 state==speaking 先 cancelCurrentDialog (打断)
///     - startTalking + 进 listening
///   抬起:
///     - finishTalking + 进 thinking（最少 600ms 守底）
///   收到 ai_voice_begin 或 tts_start: 进 speaking
///   收到 ai_voice_end 或 tts_finish: 回 idle
class VoiceChatController extends ChangeNotifier {
  final SpeechEnginePlugin _plugin = SpeechEnginePlugin();
  final AvatarBridge bridge;

  VoiceChatController({required this.bridge});

  StreamSubscription<Map<String, dynamic>>? _eventSub;

  VoiceChatState _state = VoiceChatState.idle;
  VoiceChatState get state => _state;

  final List<ChatMessage> _messages = [];
  List<ChatMessage> get messages => List.unmodifiable(_messages);

  bool _engineReady = false;
  bool get engineReady => _engineReady;

  bool _simulatorMode = false;
  bool get simulatorMode => _simulatorMode;

  /// 已加入 RTC 房间（channel_joined 触发后才为 true）
  bool _connected = false;
  bool get connected => _connected;

  /// 正在试图建立会话（startSession 已调用但还没 channel_joined）
  bool _connecting = false;
  bool get connecting => _connecting;

  bool _helloFired = false;

  String? _lastError;
  String? get lastError => _lastError;

  /// 最近 30 条原始 SDK 事件（用于调试 UI 显示）
  final List<String> _debugLog = [];
  List<String> get debugLog => List.unmodifiable(_debugLog);

  DateTime? _thinkingStartedAt;
  Timer? _thinkingMinTimer;
  Timer? _thinkingTimeoutTimer;
  static const _thinkingMinDuration = Duration(milliseconds: 250);
  static const _thinkingTimeout = Duration(seconds: 8);

  // ---------------------- 生命周期 ----------------------

  Future<void> initialize() async {
    _pushDebug('Controller.initialize()');
    _eventSub ??= _plugin.events.listen(_onEvent, onError: _onEventStreamError);
    try {
      _pushDebug('→ plugin.init(resource=${VoiceSecrets.dialogId})');
      await _plugin.init(
        appId: VoiceSecrets.appId,
        appKey: VoiceSecrets.appKey,
        token: VoiceSecrets.token,
        dialogId: VoiceSecrets.dialogId,
        uid: VoiceSecrets.uid,
        address: VoiceSecrets.address,
        uri: VoiceSecrets.uri,
        botName: VoiceSecrets.role.isEmpty ? '豆包' : VoiceSecrets.role,
        // aec 模型路径留空，让 Plugin 端自己从 Flutter assets 定位
      );
      _pushDebug('plugin.init 返回成功');
      _engineReady = true;
      notifyListeners();
    } on PlatformException catch (e) {
      if (e.code == 'SIMULATOR_NOT_SUPPORTED') {
        _simulatorMode = true;
        _pushDebug('运行于模拟器：SDK 已禁用，仅供 UI 调试');
        notifyListeners();
      } else {
        _setError('引擎初始化失败：${e.code} ${e.message ?? ''}');
      }
    } catch (e) {
      _setError('引擎初始化失败：$e');
    }
  }

  /// 进入聊天抽屉后调用：启动会话
  Future<void> startSession() async {
    if (_connecting || _connected) return;
    _pushDebug('Controller.startSession()');
    if (!_engineReady && !_simulatorMode) await initialize();
    if (_simulatorMode) {
      _setState(VoiceChatState.idle);
      return;
    }
    if (!_engineReady) {
      _pushDebug('startSession 中止：引擎未 ready');
      return;
    }
    _connecting = true;
    notifyListeners();
    try {
      await _plugin.start();
      _setState(VoiceChatState.idle);
    } catch (e) {
      _connecting = false;
      notifyListeners();
      _setError('会话启动失败：$e');
    }
  }

  /// 退出抽屉前调用
  Future<void> stopSession() async {
    _thinkingMinTimer?.cancel();
    _thinkingTimeoutTimer?.cancel();
    _helloFired = false;
    _connected = false;
    _connecting = false;
    try {
      await _plugin.stop();
    } catch (_) {}
    _setState(VoiceChatState.idle);
    notifyListeners();
  }

  /// 手动打断 AI 说话（外部可调用，如点击屏幕）
  Future<void> interruptAi() async {
    if (_state != VoiceChatState.speaking) return;
    try { await _plugin.cancelCurrentDialog(); } catch (_) {}
  }

  // ---------------------- 事件处理 ----------------------

  Future<void> _maybeFireHello() async {
    if (_helloFired) return;
    if (VoiceSecrets.helloText.isEmpty) return;
    _helloFired = true;
    try {
      _pushDebug('→ sayHello "${VoiceSecrets.helloText}"');
      await _plugin.sayHello(VoiceSecrets.helloText);
    } catch (e) {
      _pushDebug('sayHello 异常 $e');
    }
  }

  void _pushDebug(String line) {
    // 仅写入 buffer，不主动 notify。UI 由具体业务事件（消息/状态）触发刷新即可。
    final ts = DateTime.now().toString().substring(11, 19);
    _debugLog.add('[$ts] $line');
    if (_debugLog.length > 120) _debugLog.removeAt(0);
  }

  void _onEvent(Map<String, dynamic> evt) {
    final type = (evt['type'] ?? '').toString();
    if (kDebugMode) debugPrint('[VoiceChat] ← $type ${evt.toString().substring(0, evt.toString().length.clamp(0, 200))}');
    // 所有事件都进 debug 缓冲，让 release 模式也能在 UI 上看
    if (type == 'sdk_log_line' || type == 'plugin_log') {
      // SDK / Plugin 日志完整显示，不截断
      _pushDebug(evt['line']?.toString() ?? evt.toString());
    } else {
      final preview = evt.entries
          .where((e) => e.key != 'type')
          .map((e) => '${e.key}=${e.value.toString().length > 80 ? "${e.value.toString().substring(0, 80)}…" : e.value}')
          .join(' ');
      _pushDebug('$type${preview.isEmpty ? '' : ' $preview'}');
    }

    switch (type) {
      case 'engine_start':
      case 'channel_joined':
      case 'dialog_begin':
        // SpeechEngineToB 不一定回 channel_joined；engine_start 已经表示 SDK 在工作
        if (!_connected) {
          _connecting = false;
          _connected = true;
          notifyListeners();
          _maybeFireHello();
        }
        break;
      case 'engine_stop':
        _setState(VoiceChatState.idle);
        break;
      case 'engine_error':
        final code = evt['code']?.toString() ?? '?';
        final msg = evt['message']?.toString() ?? '';
        final raw = evt['raw']?.toString() ?? '';
        _pushDebug('engine_error code=$code\n  msg=$msg\n  raw=$raw');
        _setError('SDK 错误 [$code] $msg\n$raw');
        break;
      case 'subtitle_on':
        _handleSubtitle(evt['payload']?.toString(), isFinal: false);
        break;
      case 'subtitle_off':
        _handleSubtitle(evt['payload']?.toString(), isFinal: true);
        break;
      case 'ai_voice_begin':
      case 'tts_start':
        _enterSpeaking();
        break;
      case 'ai_voice_end':
      case 'tts_finish':
        _enterIdle();
        break;
      case 'dialog_cancelled':
        _enterIdle();
        break;
      case 'asr_partial':
        _handleSubtitle(evt['payload']?.toString(), isFinal: false, forceRole: ChatRole.user);
        break;
      case 'asr_final':
        _handleSubtitle(evt['payload']?.toString(), isFinal: true, forceRole: ChatRole.user);
        break;
      case 'mouth':
        final v = (evt['value'] as num?)?.toDouble() ?? 0;
        bridge.setMouthOpen(v.clamp(0.0, 1.0));
        break;
      case 'vad_begin':
        if (_state == VoiceChatState.idle) _setState(VoiceChatState.listening);
        break;
      case 'vad_end':
        // SDK 自动判停 → 服务端开始处理 → 等待 AI 回复
        if (_state == VoiceChatState.listening) _enterThinking();
        break;
      case 'dialog_end':
      case 'dialog_init':
      case 'sdk_log':
      case 'sdk_log_line':
      case 'plugin_log':
      case 'raw':
        break;
      default:
        break;
    }
  }

  void _onEventStreamError(Object err) {
    _setError('事件流异常：$err');
  }

  /// SDK 字幕 JSON 一般含 role + text (字段名要根据真机数据调整)
  /// 兼容几种常见形态。
  void _handleSubtitle(String? rawJson, {required bool isFinal, ChatRole? forceRole}) {
    if (rawJson == null || rawJson.isEmpty) return;
    Map<String, dynamic>? data;
    try {
      data = jsonDecode(rawJson) as Map<String, dynamic>;
    } catch (_) {
      data = null;
    }
    final text = data?['text']?.toString()
        ?? data?['content']?.toString()
        ?? data?['subtitle']?.toString()
        ?? '';
    if (text.isEmpty) return;

    final roleStr = (data?['role'] ?? data?['speaker'] ?? '').toString().toLowerCase();
    final role = forceRole ??
        (roleStr.contains('user') ? ChatRole.user : ChatRole.assistant);

    if (role == ChatRole.user) {
      // 看到 user 字幕意味着用户正在/已经说话
      if (_state == VoiceChatState.idle) _setState(VoiceChatState.listening);
      _appendOrUpdateUser(text, isFinal);
    } else {
      _appendOrUpdateAssistant(text, isFinal);
      // 收到 AI 字幕意味着思考结束、即将开口
      if (_state == VoiceChatState.thinking) _enterSpeaking();
    }
  }

  // ---------------------- 消息列表维护 ----------------------

  void _appendOrUpdateUser(String text, bool isFinal) {
    ChatMessage? target;
    for (final m in _messages.reversed) {
      if (m.role == ChatRole.user && !m.isFinal) { target = m; break; }
    }
    if (target == null) {
      _messages.add(ChatMessage(role: ChatRole.user, text: text, isFinal: isFinal));
    } else {
      target.text = text;
      if (isFinal) target.isFinal = true;
    }
    notifyListeners();
  }

  void _appendOrUpdateAssistant(String text, bool isFinal) {
    ChatMessage? target;
    for (final m in _messages.reversed) {
      if (m.role == ChatRole.assistant && !m.isFinal) { target = m; break; }
    }
    if (target == null) {
      _messages.add(ChatMessage(role: ChatRole.assistant, text: text, isFinal: isFinal));
    } else {
      target.text = text;
      if (isFinal) target.isFinal = true;
    }
    notifyListeners();
  }

  // ---------------------- 状态转移 ----------------------

  void _setState(VoiceChatState next) {
    if (_state == next) return;
    _state = next;
    _syncAvatar();
    notifyListeners();
  }

  void _enterThinking() {
    _thinkingStartedAt = DateTime.now();
    _thinkingMinTimer?.cancel();
    _thinkingTimeoutTimer?.cancel();
    _thinkingTimeoutTimer = Timer(_thinkingTimeout, () {
      if (_state == VoiceChatState.thinking) {
        _pushDebug('thinking timeout → idle (服务端无响应 ${_thinkingTimeout.inSeconds}s)');
        _setState(VoiceChatState.idle);
      }
    });
    _setState(VoiceChatState.thinking);
  }

  void _enterSpeaking() {
    _thinkingTimeoutTimer?.cancel();
    final waited = _thinkingStartedAt == null
        ? Duration.zero
        : DateTime.now().difference(_thinkingStartedAt!);
    final remaining = _thinkingMinDuration - waited;
    if (remaining > Duration.zero && _state == VoiceChatState.thinking) {
      _thinkingMinTimer?.cancel();
      _thinkingMinTimer = Timer(remaining, () => _setState(VoiceChatState.speaking));
    } else {
      _setState(VoiceChatState.speaking);
    }
  }

  void _enterIdle() {
    _thinkingMinTimer?.cancel();
    _thinkingTimeoutTimer?.cancel();
    _setState(VoiceChatState.idle);
  }

  void _syncAvatar() {
    switch (_state) {
      case VoiceChatState.idle:
        bridge.setState('idle');
        bridge.setMouthOpen(0);
        break;
      case VoiceChatState.listening:
        bridge.setState('listening');
        bridge.setMouthOpen(0);
        break;
      case VoiceChatState.thinking:
        bridge.setState('thinking');
        bridge.setMouthOpen(0);
        break;
      case VoiceChatState.speaking:
        bridge.setState('speaking');
        // 嘴型由 Phase 2 的 mouth_value 事件单独驱动
        break;
      case VoiceChatState.error:
        bridge.setState('idle');
        break;
    }
  }

  void _setError(String msg) {
    _lastError = msg;
    if (kDebugMode) debugPrint('[VoiceChat] ERROR: $msg');
    _setState(VoiceChatState.error);
  }

  @override
  void dispose() {
    _thinkingMinTimer?.cancel();
    _thinkingTimeoutTimer?.cancel();
    _eventSub?.cancel();
    _plugin.destroy();
    super.dispose();
  }
}
