import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';

import '../theme.dart';
import '../utils/format.dart';
import 'avatar.dart';

/// 聊天页的消息气泡：文字 / 语音条 / 文件卡片 / 图片四种，
/// 外加发送中（小菊花）与发送失败（红色感叹号）两种状态。
class MessageBubble extends StatelessWidget {
  final Message message;

  /// 是否己方发送
  final bool isMine;

  /// 己方头像信息
  final String selfName;
  final String? selfFaceURL;

  /// 对方头像信息（群聊里每条消息带各自发送者信息）
  final String peerName;
  final String? peerFaceURL;

  /// 群聊中是否显示发送者昵称（对方消息）
  final bool showSenderName;

  /// 点击语音气泡（播放）
  final void Function(Message message)? onTapVoice;

  /// 点击文件气泡（打开 / 下载）
  final void Function(Message message)? onTapFile;

  /// 点击红色感叹号重发
  final void Function(Message message)? onResend;

  /// 正在播放的语音消息 ID（用于显示播放中状态，可为空）
  final String? playingVoiceId;

  const MessageBubble({
    super.key,
    required this.message,
    required this.isMine,
    this.selfName = '',
    this.selfFaceURL,
    this.peerName = '',
    this.peerFaceURL,
    this.showSenderName = false,
    this.onTapVoice,
    this.onTapFile,
    this.onResend,
    this.playingVoiceId,
  });

  bool get _failed => message.status == MessageStatus.failed;
  bool get _sending => message.status == MessageStatus.sending;

  @override
  Widget build(BuildContext context) {
    final avatar = NameAvatar(
      name: isMine ? selfName : (message.senderNickname?.isNotEmpty == true ? message.senderNickname! : peerName),
      faceURL: isMine ? selfFaceURL : (message.senderFaceUrl?.isNotEmpty == true ? message.senderFaceUrl : peerFaceURL),
      size: 40,
    );

    final bubble = ConstrainedBox(
      constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.65),
      child: _buildContent(context),
    );

    final statusIcon = _buildStatus();

    final row = Row(
      mainAxisAlignment: isMine ? MainAxisAlignment.end : MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: isMine
          ? [statusIcon, Flexible(child: bubble), const SizedBox(width: AppGap.x2), avatar]
          : [avatar, const SizedBox(width: AppGap.x2), Flexible(child: bubble), statusIcon],
    );

    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: AppGap.x3, vertical: AppGap.x2),
      child: Column(
        crossAxisAlignment: isMine ? CrossAxisAlignment.end : CrossAxisAlignment.start,
        children: [
          if (showSenderName && !isMine && (message.senderNickname?.isNotEmpty == true))
            Padding(
              padding: const EdgeInsets.only(left: 48, bottom: AppGap.x1),
              child: Text(message.senderNickname!, style: const TextStyle(fontSize: AppFont.small, color: AppColors.textSecondary)),
            ),
          row,
          // 发送失败提示（效果图：气泡下方灰字）
          if (_failed)
            const Padding(
              padding: EdgeInsets.only(top: AppGap.x1),
              child: Text(
                '消息没发出去，点红色感叹号重发',
                style: TextStyle(fontSize: AppFont.small, color: AppColors.textSecondary),
              ),
            ),
        ],
      ),
    );
  }

  /// 发送中小菊花 / 失败红色感叹号
  Widget _buildStatus() {
    if (_sending) {
      return const Padding(
        padding: EdgeInsets.symmetric(horizontal: AppGap.x2, vertical: AppGap.x3),
        child: SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2, color: AppColors.textSecondary)),
      );
    }
    if (_failed) {
      return Padding(
        padding: const EdgeInsets.symmetric(horizontal: AppGap.x2, vertical: AppGap.x3),
        child: GestureDetector(
          onTap: () => onResend?.call(message),
          child: const Icon(Icons.error, size: 20, color: AppColors.danger),
        ),
      );
    }
    return const SizedBox.shrink();
  }

  Widget _buildContent(BuildContext context) {
    switch (message.contentType) {
      case MessageType.voice:
        return _voiceBubble();
      case MessageType.file:
        return _fileCard();
      case MessageType.picture:
        return _imageBubble();
      case MessageType.custom:
        return _textBubble(FormatUtils.messagePreview(message, isGroup: false));
      default:
        if ((message.contentType ?? 0) >= MessageType.notificationBegin) {
          // 通知类消息：居中灰字（如入群通知）
          return const SizedBox.shrink();
        }
        return _textBubble(message.textElem?.content ?? '');
    }
  }

  /// 文字气泡：己方浅蓝、对方白色
  Widget _textBubble(String text) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: AppGap.x3, vertical: AppGap.x2),
      decoration: BoxDecoration(
        color: isMine ? AppColors.bubbleMine : AppColors.bubbleOther,
        borderRadius: BorderRadius.circular(8),
      ),
      child: Text(text, style: const TextStyle(fontSize: AppFont.body, color: AppColors.textPrimary)),
    );
  }

  /// 语音气泡：喇叭图标 + 秒数；未读语音右侧小红点
  Widget _voiceBubble() {
    final duration = message.soundElem?.duration ?? 0;
    final playing = playingVoiceId != null && playingVoiceId == message.clientMsgID;
    // 宽度随时长增加，封顶
    final width = 72.0 + (duration > 30 ? 60 : duration * 2);
    final unread = !isMine && message.isRead == false;

    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        GestureDetector(
          onTap: () => onTapVoice?.call(message),
          child: Container(
            width: width,
            padding: const EdgeInsets.symmetric(horizontal: AppGap.x3, vertical: AppGap.x2),
            decoration: BoxDecoration(
              color: isMine ? AppColors.bubbleMine : AppColors.bubbleOther,
              borderRadius: BorderRadius.circular(8),
            ),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: isMine ? MainAxisAlignment.end : MainAxisAlignment.start,
              children: isMine
                  ? [
                      Text('$duration″', style: const TextStyle(fontSize: AppFont.body, color: AppColors.textPrimary)),
                      const SizedBox(width: AppGap.x2),
                      Icon(playing ? Icons.volume_up : Icons.volume_up_outlined, size: 20, color: AppColors.textPrimary),
                    ]
                  : [
                      Icon(playing ? Icons.volume_up : Icons.volume_up_outlined, size: 20, color: AppColors.textPrimary),
                      const SizedBox(width: AppGap.x2),
                      Text('$duration″', style: const TextStyle(fontSize: AppFont.body, color: AppColors.textPrimary)),
                    ],
            ),
          ),
        ),
        if (unread)
          Container(
            width: 8,
            height: 8,
            margin: const EdgeInsets.only(left: AppGap.x1),
            decoration: const BoxDecoration(color: AppColors.danger, shape: BoxShape.circle),
          ),
      ],
    );
  }

  /// 文件气泡：卡片样式（文件图标、文件名、大小）
  Widget _fileCard() {
    final name = message.fileElem?.fileName ?? '未知文件';
    final size = FormatUtils.fileSize(message.fileElem?.fileSize);
    return GestureDetector(
      onTap: () => onTapFile?.call(message),
      child: Container(
        padding: const EdgeInsets.all(AppGap.x3),
        decoration: BoxDecoration(
          color: isMine ? AppColors.bubbleMine : AppColors.bubbleOther,
          borderRadius: BorderRadius.circular(8),
        ),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              width: 44,
              height: 44,
              decoration: BoxDecoration(
                color: AppColors.pageBg,
                borderRadius: BorderRadius.circular(8),
              ),
              child: const Icon(Icons.insert_drive_file_outlined, size: 28, color: AppColors.primary),
            ),
            const SizedBox(width: AppGap.x2),
            Flexible(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    name,
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                    style: const TextStyle(fontSize: AppFont.body, color: AppColors.textPrimary),
                  ),
                  const SizedBox(height: AppGap.x1),
                  Text(size, style: const TextStyle(fontSize: AppFont.small, color: AppColors.textSecondary)),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  /// 图片气泡：本地优先，其次网络图
  Widget _imageBubble() {
    final localPath = message.pictureElem?.sourcePath;
    final url = message.pictureElem?.snapshotPicture?.url ?? message.pictureElem?.sourcePicture?.url;
    Widget child;
    if (localPath != null && localPath.isNotEmpty && File(localPath).existsSync()) {
      child = Image.file(File(localPath), fit: BoxFit.cover);
    } else if (url != null && url.isNotEmpty) {
      child = Image.network(
        url,
        fit: BoxFit.cover,
        errorBuilder: (_, __, ___) => _imagePlaceholder(),
        loadingBuilder: (_, c, p) => p == null ? c : _imagePlaceholder(),
      );
    } else {
      child = _imagePlaceholder();
    }
    return ClipRRect(
      borderRadius: BorderRadius.circular(8),
      child: ConstrainedBox(
        constraints: const BoxConstraints(maxWidth: 160, maxHeight: 200),
        child: child,
      ),
    );
  }

  Widget _imagePlaceholder() {
    return Container(
      width: 120,
      height: 120,
      color: AppColors.searchBg,
      alignment: Alignment.center,
      child: const Icon(Icons.image_outlined, size: 40, color: AppColors.textSecondary),
    );
  }
}
