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

import '../../../../api/marianumcloud/talk/actions/talk_actions.dart';
import '../../../../api/marianumcloud/talk/chat/get_chat_response.dart';
import '../../../../api/marianumcloud/talk/react_message/react_message.dart';
import '../../../../api/marianumcloud/talk/react_message/react_message_params.dart';
import '../../../../api/marianumcloud/talk/room/get_room_response.dart';
import '../../../../routing/app_routes.dart';
import '../../../../share_intent/remote_file_ref.dart';
import '../../../../state/app/modules/chat/bloc/chat_bloc.dart';
import '../../../../utils/clipboard_helper.dart';
import '../../../../utils/emoji_detection.dart';
import '../../../../widget/app_progress_indicator.dart';
import '../../../../widget/async_action_button.dart';
import '../../../../widget/confirm_dialog.dart';
import '../../../../widget/debug/debug_tile.dart';
import '../../../../widget/demo_restricted.dart';
import '../../../../widget/details_bottom_sheet.dart';
import '../../../../widget/emoji_picker_dialog.dart';
import '../../../../widget/emoji_text.dart';
import '../data/open_direct_chat.dart';

const _commonReactions = <String>['👍', '👎', '❤️', '😆', '😮', '😢'];

/// Upper bound on how many of a message's own emojis we surface as reactions,
/// so an emoji-heavy message doesn't blow up the reaction row.
const _maxMessageReactions = 3;

/// The emojis contained in [bubbleData] itself, offered as extra reactions
/// next to the standard set (most-frequent first).
///
/// Deduped skin-tone-neutrally so a tone variant of an emoji already in the
/// standard set (e.g. 👍🏻 next to 👍) isn't offered a second time, while a
/// message's own tone choice is preserved for emojis not in the set.
List<String> _messageReactionsFor(GetChatResponseObject bubbleData) {
  final covered = _commonReactions.map(emojiSkinToneNeutral).toSet();
  final result = <String>[];
  for (final emoji in extractEmojis(bubbleData.message)) {
    if (!covered.add(emojiSkinToneNeutral(emoji))) continue;
    result.add(emoji);
    if (result.length >= _maxMessageReactions) break;
  }
  return result;
}

RichObjectString? _attachedFile(GetChatResponseObject bubbleData) {
  final file = bubbleData.messageParameters?['file'];
  if (file == null ||
      file.path == null ||
      file.type != RichObjectStringObjectType.file) {
    return null;
  }
  return file;
}

void showChatMessageOptionsDialog(
  BuildContext context, {
  required GetRoomResponseObject chatData,
  required GetChatResponseObject bubbleData,
  required bool isSender,
  required void Function({bool renew}) onRefetch,
}) {
  final parentContext = context;
  final canReact =
      bubbleData.messageType == GetRoomResponseObjectMessageType.comment;
  final hasReactions = bubbleData.reactions?.isNotEmpty ?? false;
  final canDelete =
      isSender &&
      DateTime.fromMillisecondsSinceEpoch(
        bubbleData.timestamp * 1000,
      ).add(const Duration(hours: 6)).isAfter(DateTime.now());
  final attachedFile = _attachedFile(bubbleData);

  showDetailsBottomSheet(
    context,
    children: (sheetCtx) => [
      if (canReact)
        _ReactionsRow(
          chatToken: chatData.token,
          messageId: bubbleData.id,
          reactions: _commonReactions,
          messageReactions: _messageReactionsFor(bubbleData),
          onRefetch: onRefetch,
          sheetContext: sheetCtx,
        ),
      if (bubbleData.isReplyable)
        ListTile(
          leading: const Icon(Icons.reply_outlined),
          title: const Text('Antworten'),
          onTap: () {
            if (guardDemoAction(sheetCtx)) return;
            sheetCtx.read<ChatBloc>().setReferenceMessageId(bubbleData.id);
            Navigator.of(sheetCtx).pop();
          },
        ),
      if (canReact && hasReactions)
        ListTile(
          leading: const Icon(Icons.emoji_emotions_outlined),
          title: const Text('Reaktionen'),
          onTap: () {
            Navigator.of(sheetCtx).pop();
            if (!parentContext.mounted) return;
            AppRoutes.openMessageReactions(
              parentContext,
              chatData.token,
              bubbleData.id,
            );
          },
        ),
      if (bubbleData.message != '{file}')
        ListTile(
          leading: const Icon(Icons.copy),
          title: const Text('Nachricht kopieren'),
          onTap: () {
            copyToClipboard(parentContext, bubbleData.message);
            Navigator.of(sheetCtx).pop();
          },
        ),
      if (attachedFile != null)
        ListTile(
          leading: const Icon(Icons.cloud_outlined),
          title: const Text('In Cloud speichern'),
          onTap: () {
            if (guardDemoAction(sheetCtx)) return;
            Navigator.of(sheetCtx).pop();
            if (!parentContext.mounted) return;
            AppRoutes.openInternalSaveToFolder(
              parentContext,
              RemoteFileRef.fromTalk(attachedFile),
            );
          },
        ),
      if (canReact && (bubbleData.message != '{file}' || attachedFile != null))
        ListTile(
          leading: const Icon(Icons.shortcut_outlined),
          title: const Text('Weiterleiten'),
          onTap: () {
            if (guardDemoAction(sheetCtx)) return;
            Navigator.of(sheetCtx).pop();
            if (!parentContext.mounted) return;
            AppRoutes.openForwardMessageToChat(
              parentContext,
              text: bubbleData.message == '{file}' ? null : bubbleData.message,
              file: attachedFile != null
                  ? RemoteFileRef.fromTalk(attachedFile)
                  : null,
            );
          },
        ),
      if (canReact &&
          !isSender &&
          chatData.type != GetRoomResponseObjectConversationType.oneToOne &&
          bubbleData.actorType ==
              GetRoomResponseObjectMessageActorType.user)
        ListTile(
          leading: const Icon(Icons.sms_outlined),
          title: Text('Private Nachricht an ${bubbleData.actorDisplayName}'),
          onTap: () {
            Navigator.of(sheetCtx).pop();
            if (!parentContext.mounted) return;
            openOrCreateDirectChat(
              parentContext,
              actorId: bubbleData.actorId,
              actorDisplayName: bubbleData.actorDisplayName,
            );
          },
        ),
      if (canDelete)
        ListTile(
          leading: const Icon(Icons.delete_outline),
          title: const Text('Nachricht löschen'),
          onTap: () {
            if (guardDemoAction(sheetCtx)) return;
            ConfirmDialog(
              title: 'Nachricht löschen?',
              content: 'Die Nachricht wird für alle Teilnehmer gelöscht.',
              confirmButton: 'Löschen',
              onConfirmAsync: () async {
                await DeleteMessage(chatData.token, bubbleData.id).run();
                if (!sheetCtx.mounted) return;
                final bloc = sheetCtx.read<ChatBloc>();
                Navigator.of(sheetCtx).pop();
                bloc.refresh();
              },
            ).asDialog(sheetCtx);
          },
        ),
      DebugTile(sheetCtx).jsonData(bubbleData.toJson()),
    ],
  );
}

class _ReactionsRow extends StatefulWidget {
  final String chatToken;
  final int messageId;
  final List<String> reactions;
  final List<String> messageReactions;
  final void Function({bool renew}) onRefetch;
  final BuildContext sheetContext;

  const _ReactionsRow({
    required this.chatToken,
    required this.messageId,
    required this.reactions,
    required this.messageReactions,
    required this.onRefetch,
    required this.sheetContext,
  });

  @override
  State<_ReactionsRow> createState() => _ReactionsRowState();
}

class _ReactionsRowState extends State<_ReactionsRow> {
  final AsyncActionController _controller = AsyncActionController();

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

  Future<void> _react(String emoji) async {
    if (guardDemoAction(context)) return;
    final ok = await _controller.run(() async {
      await ReactMessage(
        chatToken: widget.chatToken,
        messageId: widget.messageId,
        params: ReactMessageParams(emoji),
      ).run();
    });
    if (!mounted) return;
    if (ok) {
      widget.onRefetch(renew: true);
      if (widget.sheetContext.mounted) Navigator.of(widget.sheetContext).pop();
    }
  }

  @override
  Widget build(BuildContext context) => AnimatedBuilder(
    animation: _controller,
    builder: (context, _) {
      final busy = _controller.busy;
      final err = _controller.error;
      return Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Wrap(
            alignment: WrapAlignment.center,
            crossAxisAlignment: WrapCrossAlignment.center,
            children: [
              ...widget.reactions.map((emoji) => _emojiButton(emoji, busy)),
              if (widget.messageReactions.isNotEmpty) ...[
                _groupDivider(context),
                ...widget.messageReactions.map(
                  (emoji) => _emojiButton(emoji, busy),
                ),
              ],
              _groupDivider(context),
              IconButton(
                tooltip: 'Reaktion hinzufügen',
                onPressed: busy ? null : () => _showEmojiPicker(context),
                style: IconButton.styleFrom(
                  padding: EdgeInsets.zero,
                  tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                  minimumSize: const Size(40, 40),
                ),
                icon: busy
                    ? const AppProgressIndicator.small()
                    : const Icon(Icons.add_circle_outline_outlined),
              ),
            ],
          ),
          if (err != null)
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
              child: Text(
                err,
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: Theme.of(context).colorScheme.error,
                  fontSize: 12,
                ),
              ),
            ),
          const Divider(),
        ],
      );
    },
  );

  Widget _emojiButton(String emoji, bool busy) => TextButton(
    style: TextButton.styleFrom(
      padding: EdgeInsets.zero,
      tapTargetSize: MaterialTapTargetSize.shrinkWrap,
      minimumSize: const Size(40, 40),
    ),
    onPressed: busy ? null : () => _react(emoji),
    child: EmojiText(emoji, size: EmojiText.sizeLarge),
  );

  Widget _groupDivider(BuildContext context) => Container(
    width: 1,
    height: 24,
    margin: const EdgeInsets.symmetric(horizontal: 6),
    color: Theme.of(context).dividerColor,
  );

  Future<void> _showEmojiPicker(BuildContext rowContext) async {
    final emoji = await showEmojiPicker(rowContext, title: 'Reagieren');
    if (emoji != null && mounted) await _react(emoji);
  }
}
