import 'dart:async';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
import 'package:image_picker/image_picker.dart';
import 'package:just_audio/just_audio.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';

import '../services/call_service.dart';
import '../services/im_service.dart';
import '../services/message_send_service.dart';
import '../theme.dart';
import '../utils/format.dart';
import '../widgets/chat_input_bar.dart';
import '../widgets/message_bubble.dart';
import 'call_screen.dart';

/// 单聊 / 群聊聊天页（效果图 m2）
class ChatScreen extends StatefulWidget {
  final ConversationInfo conversation;

  const ChatScreen({super.key, required this.conversation});

  @override
  State<ChatScreen> createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  /// 消息列表，新消息在前（配合 reverse 列表）
  final List<Message> _messages = [];
  final ScrollController _scroll = ScrollController();
  final AudioPlayer _player = AudioPlayer();
  final Dio _dio = Dio();

  StreamSubscription<Message>? _msgSub;
  StreamSubscription<String>? _revokeSub;

  bool _loadingHistory = false;
  bool _hasMore = true;
  String? _playingVoiceId;

  static const int _pageSize = 30;

  /// 相邻消息间隔超过 5 分钟显示时间分隔条
  static const int _dividerGapMillis = 5 * 60 * 1000;

  ConversationInfo get _conv => widget.conversation;
  bool get _isGroup =>
      _conv.conversationType == ConversationType.superGroup || _conv.conversationType == ConversationType.group;
  String get _peerID => _conv.userID ?? '';
  String get _groupID => _conv.groupID ?? '';
  String get _title => _conv.showName ?? '';

  @override
  void initState() {
    super.initState();
    _loadHistory(first: true);
    IMService.instance.markConversationRead(_conv.conversationID);
    _msgSub = IMService.instance.onNewMessage.listen(_onNewMessage);
    _revokeSub = IMService.instance.onMessageRevoked.listen(_onRevoked);
    _scroll.addListener(() {
      // 滚动到顶部加载更早的历史消息
      if (_scroll.position.pixels >= _scroll.position.maxScrollExtent - 40) {
        _loadHistory();
      }
    });
  }

  @override
  void dispose() {
    _msgSub?.cancel();
    _revokeSub?.cancel();
    _scroll.dispose();
    _player.dispose();
    super.dispose();
  }

  // ---------------- 历史消息 ----------------

  Future<void> _loadHistory({bool first = false}) async {
    if (_loadingHistory || (!_hasMore && !first)) return;
    _loadingHistory = true;
    try {
      final result = await OpenIM.iMManager.messageManager.getAdvancedHistoryMessageList(
        conversationID: _conv.conversationID,
        count: _pageSize,
        startMsg: first ? null : (_messages.isEmpty ? null : _messages.last),
      );
      final list = result.messageList ?? [];
      if (!mounted) return;
      setState(() {
        if (first) _messages.clear();
        _messages.addAll(list);
        if (list.length < _pageSize || result.isEnd == true) _hasMore = false;
      });
    } catch (_) {
      if (first && mounted) _toast('消息没加载出来，请检查网络');
    } finally {
      _loadingHistory = false;
    }
  }

  // ---------------- 新消息 / 撤回 ----------------

  bool _belongsHere(Message msg) {
    if (_isGroup) return msg.groupID == _groupID;
    final myID = IMService.instance.currentUserID;
    // 对方发来的，或自己在别的设备发的
    return (msg.sendID == _peerID && msg.recvID == myID) || (msg.sendID == myID && msg.recvID == _peerID);
  }

  void _onNewMessage(Message msg) {
    if (!_belongsHere(msg)) return;
    if (!mounted) return;
    setState(() {
      final idx = _messages.indexWhere((m) => m.clientMsgID == msg.clientMsgID);
      if (idx >= 0) {
        _messages[idx] = msg;
      } else {
        _messages.insert(0, msg);
      }
    });
    IMService.instance.markConversationRead(_conv.conversationID);
  }

  void _onRevoked(String clientMsgID) {
    final idx = _messages.indexWhere((m) => m.clientMsgID == clientMsgID);
    if (idx < 0 || !mounted) return;
    setState(() => _messages.removeAt(idx));
    _toast('对方撤回了一条消息');
  }

  // ---------------- 发送 ----------------

  /// 统一发送入口：文字/表情/语音/图片/文件都经过这里。
  /// 失败时用 [MessageSendService] 的中文提示，不再只标红感叹号。
  Future<void> _sendMessage(Message message) async {
    setState(() {
      message.status = MessageStatus.sending;
      _messages.insert(0, message);
    });
    if (_scroll.hasClients) _scroll.jumpTo(0);
    try {
      final sent = await MessageSendService.instance.send(
        message: message,
        userID: _isGroup ? null : _peerID,
        groupID: _isGroup ? _groupID : null,
      );
      if (!mounted) return;
      setState(() => message.status = sent.status ?? MessageStatus.succeeded);
    } catch (e) {
      if (!mounted) return;
      setState(() => message.status = MessageStatus.failed);
      _toast(e is Exception ? e.toString() : '消息没发出去，请重试');
    }
  }

  /// 点红色感叹号重发
  Future<void> _resend(Message message) async {
    setState(() => message.status = MessageStatus.sending);
    try {
      final sent = await MessageSendService.instance.send(
        message: message,
        userID: _isGroup ? null : _peerID,
        groupID: _isGroup ? _groupID : null,
      );
      if (!mounted) return;
      setState(() => message.status = sent.status ?? MessageStatus.succeeded);
    } catch (e) {
      if (!mounted) return;
      setState(() => message.status = MessageStatus.failed);
      _toast(e is Exception ? e.toString() : '消息没发出去，请重试');
    }
  }

  Future<void> _sendText(String text) async {
    try {
      final message = await OpenIM.iMManager.messageManager.createTextMessage(text: text);
      _sendMessage(message);
    } catch (_) {
      _toast('消息没发出去，请重试');
    }
  }

  Future<void> _sendVoice(String path, int duration) async {
    try {
      final message = await OpenIM.iMManager.messageManager.createSoundMessageFromFullPath(
        soundPath: path,
        duration: duration,
      );
      _sendMessage(message);
    } catch (_) {
      _toast('语音没发出去，请重试');
    }
  }

  Future<void> _pickAndSendImage() async {
    try {
      final picked = await ImagePicker().pickImage(source: ImageSource.gallery, imageQuality: 80);
      if (picked == null) return;
      final message = await OpenIM.iMManager.messageManager.createImageMessageFromFullPath(imagePath: picked.path);
      _sendMessage(message);
    } catch (_) {
      _toast('图片没发出去，请重试');
    }
  }

  Future<void> _pickAndSendFile() async {
    try {
      final result = await FilePicker.platform.pickFiles();
      final file = result?.files.single;
      if (file == null || file.path == null) return;
      final message = await OpenIM.iMManager.messageManager.createFileMessageFromFullPath(
        filePath: file.path!,
        fileName: file.name,
      );
      _sendMessage(message);
    } catch (_) {
      _toast('文件没发出去，请重试');
    }
  }

  // ---------------- 语音播放 / 文件打开 ----------------

  Future<void> _playVoice(Message message) async {
    try {
      // 再点一次同一条语音 = 停止
      if (_playingVoiceId == message.clientMsgID && _player.playing) {
        await _player.stop();
        if (mounted) setState(() => _playingVoiceId = null);
        return;
      }
      final localPath = message.soundElem?.soundPath;
      final url = message.soundElem?.sourceUrl;
      if (localPath != null && localPath.isNotEmpty && File(localPath).existsSync()) {
        await _player.setFilePath(localPath);
      } else if (url != null && url.isNotEmpty) {
        await _player.setUrl(url);
      } else {
        _toast('语音文件找不到了');
        return;
      }
      if (mounted) setState(() => _playingVoiceId = message.clientMsgID);
      // 播放后去掉未读红点
      setState(() => message.isRead = true);
      await _player.play();
      if (mounted) setState(() => _playingVoiceId = null);
    } catch (_) {
      if (mounted) setState(() => _playingVoiceId = null);
      _toast('语音播放失败');
    }
  }

  Future<void> _openFile(Message message) async {
    final localPath = message.fileElem?.filePath;
    final url = message.fileElem?.sourceUrl;
    final fileName = message.fileElem?.fileName ?? 'file';
    try {
      String path;
      if (localPath != null && localPath.isNotEmpty && File(localPath).existsSync()) {
        path = localPath;
      } else if (url != null && url.isNotEmpty) {
        _toast('正在下载，请稍候');
        final dir = await getTemporaryDirectory();
        path = '${dir.path}/$fileName';
        await _dio.download(url, path);
      } else {
        _toast('文件找不到了');
        return;
      }
      final result = await OpenFilex.open(path);
      if (result.type != ResultType.done) {
        _toast('没有能打开这个文件的应用');
      }
    } catch (_) {
      _toast('文件打不开，请稍后再试');
    }
  }

  // ---------------- 语音通话 ----------------

  Future<void> _startVoiceCall() async {
    final error = await CallService.instance.startCall(peerUserID: _peerID, peerName: _title);
    if (!mounted) return;
    if (error != null) {
      _toast(error);
      return;
    }
    Navigator.of(context).push(MaterialPageRoute(builder: (_) => const CallScreen(), fullscreenDialog: true));
  }

  void _toast(String text) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(text), duration: const Duration(seconds: 2)));
  }

  // ---------------- 界面 ----------------

  @override
  Widget build(BuildContext context) {
    final self = IMService.instance.selfInfo;
    return Scaffold(
      backgroundColor: AppColors.chatBg,
      appBar: AppBar(
        title: Text(_title),
        actions: [
          if (!_isGroup)
            IconButton(
              icon: const Icon(Icons.more_horiz),
              onPressed: () {
                showModalBottomSheet(
                  context: context,
                  builder: (ctx) => SafeArea(
                    child: ListTile(
                      leading: const Icon(Icons.phone_outlined),
                      title: const Text('语音通话'),
                      onTap: () {
                        Navigator.of(ctx).pop();
                        _startVoiceCall();
                      },
                    ),
                  ),
                );
              },
            ),
        ],
      ),
      body: Column(
        children: [
          Expanded(
            child: GestureDetector(
              onTap: () => FocusScope.of(context).unfocus(),
              child: ListView.builder(
                controller: _scroll,
                reverse: true,
                padding: const EdgeInsets.symmetric(vertical: AppGap.x2),
                itemCount: _messages.length,
                itemBuilder: (context, i) {
                  final msg = _messages[i];
                  return Column(
                    children: [
                      _buildMessageRow(msg, self),
                      if (_showDividerAt(i)) _timeDivider(msg),
                    ],
                  );
                },
              ),
            ),
          ),
          SafeArea(
            top: false,
            child: ChatInputBar(
              onSendText: _sendText,
              onSendVoice: _sendVoice,
              onPickImage: _pickAndSendImage,
              onPickFile: _pickAndSendFile,
              onVoiceCall: _isGroup ? null : _startVoiceCall,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildMessageRow(Message msg, UserInfo? self) {
    final isMine = msg.sendID == IMService.instance.currentUserID;
    // 通知类消息（如入群提示）：居中灰字
    if ((msg.contentType ?? 0) >= MessageType.notificationBegin) {
      return Padding(
        padding: const EdgeInsets.symmetric(vertical: AppGap.x2),
        child: Center(
          child: Text(
            FormatUtils.messagePreview(msg, isGroup: _isGroup),
            style: const TextStyle(fontSize: AppFont.small, color: AppColors.textSecondary),
          ),
        ),
      );
    }
    return MessageBubble(
      message: msg,
      isMine: isMine,
      selfName: self?.nickname ?? '',
      selfFaceURL: self?.faceURL,
      peerName: _title,
      peerFaceURL: _isGroup ? null : _conv.faceURL,
      showSenderName: _isGroup,
      playingVoiceId: _playingVoiceId,
      onTapVoice: _playVoice,
      onTapFile: _openFile,
      onResend: _resend,
    );
  }

  /// 与上一条（更旧的）消息间隔超过 5 分钟时显示时间分隔条
  bool _showDividerAt(int i) {
    final current = _messages[i].sendTime ?? 0;
    if (current <= 0) return false;
    if (i == _messages.length - 1) return true; // 最早一条也显示
    final older = _messages[i + 1].sendTime ?? 0;
    return current - older > _dividerGapMillis;
  }

  Widget _timeDivider(Message msg) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: AppGap.x2),
      child: Center(
        child: Text(
          FormatUtils.chatDividerTime(msg.sendTime ?? 0),
          style: const TextStyle(fontSize: AppFont.small, color: AppColors.textSecondary),
        ),
      ),
    );
  }
}
