// Version: 1.3.0 | Created: 2026-04-01 | Updated: 2026-04-27
// Full chat screen — timeline + input + typing indicators + read receipts
// + long-press context menu (reply, react, copy, delete) + room options sheet.

import 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart' show MatrixFile, Room;

import '../../../core/network/matrix_client.dart';
import '../../../shared/utils/matrix_id.dart';
import '../../../shared/utils/mxc_url.dart';
import '../../../shared/widgets/matrix_avatar.dart';
import '../../rooms/presentation/user_search_dialog.dart';
import '../domain/message_model.dart';
import 'chat_controller.dart';
import 'message_bubble.dart';
import 'message_input.dart';

class ChatScreen extends ConsumerStatefulWidget {
  const ChatScreen({super.key, required this.roomId});

  final String roomId;

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

class _ChatScreenState extends ConsumerState<ChatScreen> {
  String? _replyToEventId;
  String? _replyToSenderName;
  String? _replyToBody;

  String get _decodedRoomId => Uri.decodeComponent(widget.roomId);

  void _showRoomOptions(BuildContext context, Room room) {
    showModalBottomSheet<void>(
      context: context,
      isScrollControlled: true,
      builder: (_) => _RoomOptionsSheet(room: room),
    );
  }

  void _setReply(MessageModel message) {
    setState(() {
      _replyToEventId = message.eventId;
      _replyToSenderName = message.senderDisplayName;
      _replyToBody = message.body ?? '';
    });
  }

  void _clearReply() {
    setState(() {
      _replyToEventId = null;
      _replyToSenderName = null;
      _replyToBody = null;
    });
  }

  @override
  Widget build(BuildContext context) {
    final client = ref.watch(matrixClientProvider);
    final room = client.getRoomById(_decodedRoomId);
    final roomName = room?.getLocalizedDisplayname() ?? 'Chat';
    final roomAvatar = resolveMxcUrl(client, room?.avatar);

    return Scaffold(
      appBar: AppBar(
        titleSpacing: 0,
        title: Row(
          children: [
            MatrixAvatar(name: roomName, avatarUrl: roomAvatar, radius: 18),
            const SizedBox(width: 10),
            Flexible(child: Text(roomName, overflow: TextOverflow.ellipsis)),
          ],
        ),
        actions: [
          // Voice call
          IconButton(
            icon: const Icon(Icons.call),
            tooltip: 'Voice call',
            onPressed: () => context.push(
              '/calls/${Uri.encodeComponent(_decodedRoomId)}?video=0',
            ),
          ),
          // Video call
          IconButton(
            icon: const Icon(Icons.videocam_outlined),
            tooltip: 'Video call',
            onPressed: () => context.push(
              '/calls/${Uri.encodeComponent(_decodedRoomId)}?video=1',
            ),
          ),
          IconButton(
            icon: const Icon(Icons.more_vert),
            tooltip: 'Room options',
            onPressed: room != null
                ? () => _showRoomOptions(context, room)
                : null,
          ),
        ],
      ),
      body: Column(
        children: [
          Expanded(
            child: _Timeline(roomId: _decodedRoomId, onReply: _setReply),
          ),
          _TypingIndicator(roomId: _decodedRoomId),
          _Input(
            roomId: _decodedRoomId,
            replyToEventId: _replyToEventId,
            replyToSenderName: _replyToSenderName,
            replyToBody: _replyToBody,
            onCancelReply: _clearReply,
          ),
        ],
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Timeline
// ---------------------------------------------------------------------------

class _Timeline extends ConsumerWidget {
  const _Timeline({required this.roomId, required this.onReply});

  final String roomId;
  final void Function(MessageModel) onReply;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final timelineAsync = ref.watch(chatTimelineProvider(roomId));

    return timelineAsync.when(
      loading: () => const Center(child: CircularProgressIndicator()),
      error: (error, _) => Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Text('Could not load messages: $error'),
        ),
      ),
      data: (messages) {
        if (messages.isEmpty) {
          return Center(
            child: Text(
              'No messages yet. Say hello!',
              style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                color: Theme.of(context).colorScheme.onSurface.withAlpha(102),
              ),
            ),
          );
        }

        return ListView.builder(
          reverse: true,
          padding: const EdgeInsets.symmetric(vertical: 8),
          itemCount: messages.length,
          itemBuilder: (context, index) {
            final message = messages[index];
            return _MessageWithGestures(
              message: message,
              roomId: roomId,
              onReply: () => onReply(message),
            );
          },
        );
      },
    );
  }
}

// ---------------------------------------------------------------------------
// Long-press context menu
// ---------------------------------------------------------------------------

class _MessageWithGestures extends ConsumerWidget {
  const _MessageWithGestures({
    required this.message,
    required this.roomId,
    required this.onReply,
  });

  final MessageModel message;
  final String roomId;
  final VoidCallback onReply;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return GestureDetector(
      onLongPress: () => _showContextMenu(context, ref),
      child: MessageBubble(message: message),
    );
  }

  void _showContextMenu(BuildContext context, WidgetRef ref) {
    showModalBottomSheet<void>(
      context: context,
      builder: (_) => _MessageContextMenu(
        message: message,
        roomId: roomId,
        onReply: () {
          Navigator.pop(context);
          onReply();
        },
        onReact: () {
          Navigator.pop(context);
          _showEmojiPicker(context, ref);
        },
        onCopy: () {
          Clipboard.setData(ClipboardData(text: message.body ?? ''));
          Navigator.pop(context);
          ScaffoldMessenger.of(
            context,
          ).showSnackBar(const SnackBar(content: Text('Message copied.')));
        },
        onDelete: message.isMine
            ? () async {
                Navigator.pop(context);
                await ref
                    .read(deleteMessageProvider.notifier)
                    .delete(roomId, message.eventId);
              }
            : null,
      ),
    );
  }

  void _showEmojiPicker(BuildContext context, WidgetRef ref) {
    showModalBottomSheet<void>(
      context: context,
      builder: (_) => SizedBox(
        height: 320,
        child: EmojiPicker(
          onEmojiSelected: (_, emoji) async {
            Navigator.pop(context);
            await ref
                .read(sendReactionProvider.notifier)
                .react(roomId, message.eventId, emoji.emoji);
          },
          config: const Config(
            emojiViewConfig: EmojiViewConfig(columns: 8, emojiSizeMax: 28),
          ),
        ),
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Room options sheet
// ---------------------------------------------------------------------------

class _RoomOptionsSheet extends ConsumerStatefulWidget {
  const _RoomOptionsSheet({required this.room});
  final Room room;

  @override
  ConsumerState<_RoomOptionsSheet> createState() => _RoomOptionsSheetState();
}

class _RoomOptionsSheetState extends ConsumerState<_RoomOptionsSheet> {
  bool _leaving = false;

  Future<void> _leaveRoom(BuildContext context) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (_) => AlertDialog(
        title: const Text('Leave room?'),
        content: Text(
          'You will leave "${widget.room.getLocalizedDisplayname()}". '
          'You can rejoin if you have an invite.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            style: TextButton.styleFrom(
              foregroundColor: Theme.of(context).colorScheme.error,
            ),
            child: const Text('Leave'),
          ),
        ],
      ),
    );

    if (confirmed != true || !mounted) return;

    setState(() => _leaving = true);
    try {
      await widget.room.leave();
      if (mounted) {
        Navigator.of(context).pop(); // close sheet
        GoRouter.of(context).go('/rooms');
      }
    } on Exception catch (e) {
      if (mounted) {
        setState(() => _leaving = false);
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Could not leave room: $e')),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final client = ref.watch(matrixClientProvider);
    final theme = Theme.of(context);
    final room = widget.room;
    final members = room.getParticipants();
    final canInvite = room.canInvite;

    return SafeArea(
      child: ConstrainedBox(
        constraints: BoxConstraints(
          maxHeight: MediaQuery.of(context).size.height * 0.75,
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Header
            Padding(
              padding: const EdgeInsets.fromLTRB(20, 16, 16, 4),
              child: Row(
                children: [
                  Expanded(
                    child: Text(
                      room.getLocalizedDisplayname(),
                      style: theme.textTheme.titleMedium?.copyWith(
                        fontWeight: FontWeight.w600,
                      ),
                      overflow: TextOverflow.ellipsis,
                    ),
                  ),
                  IconButton(
                    icon: const Icon(Icons.close),
                    onPressed: () => Navigator.of(context).pop(),
                  ),
                ],
              ),
            ),

            // Members section
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 4),
              child: Text(
                'Members (${members.length})',
                style: theme.textTheme.labelMedium?.copyWith(
                  color: theme.colorScheme.primary,
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
            Flexible(
              child: ListView.builder(
                shrinkWrap: true,
                itemCount: members.length,
                itemBuilder: (context, index) {
                  final member = members[index];
                  final name =
                      member.displayName ?? member.id.matrixLocalpart;
                  final avatarUrl =
                      resolveMxcUrl(client, member.avatarUrl);
                  final isMe = member.id == client.userID;

                  return ListTile(
                    dense: true,
                    leading: MatrixAvatar(
                      name: name,
                      avatarUrl: avatarUrl,
                      radius: 16,
                    ),
                    title: Text(
                      isMe ? '$name (you)' : name,
                      style: theme.textTheme.bodyMedium,
                    ),
                    subtitle: Text(
                      member.id,
                      style: theme.textTheme.bodySmall?.copyWith(
                        color: theme.colorScheme.onSurface.withAlpha(120),
                      ),
                    ),
                  );
                },
              ),
            ),

            const Divider(),

            // Actions
            if (canInvite)
              ListTile(
                leading: const Icon(Icons.person_add_outlined),
                title: const Text('Invite someone'),
                onTap: () {
                  Navigator.of(context).pop();
                  showUserSearchDialog(context);
                },
              ),
            ListTile(
              leading: _leaving
                  ? const SizedBox(
                      width: 24,
                      height: 24,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : Icon(
                      Icons.exit_to_app,
                      color: theme.colorScheme.error,
                    ),
              title: Text(
                'Leave room',
                style: TextStyle(color: theme.colorScheme.error),
              ),
              enabled: !_leaving,
              onTap: () => _leaveRoom(context),
            ),
          ],
        ),
      ),
    );
  }
}

class _MessageContextMenu extends StatelessWidget {
  const _MessageContextMenu({
    required this.message,
    required this.roomId,
    required this.onReply,
    required this.onReact,
    required this.onCopy,
    this.onDelete,
  });

  final MessageModel message;
  final String roomId;
  final VoidCallback onReply;
  final VoidCallback onReact;
  final VoidCallback onCopy;
  final VoidCallback? onDelete;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          ListTile(
            leading: const Icon(Icons.reply),
            title: const Text('Reply'),
            onTap: onReply,
          ),
          ListTile(
            leading: const Icon(Icons.add_reaction_outlined),
            title: const Text('React'),
            onTap: onReact,
          ),
          if (message.body != null)
            ListTile(
              leading: const Icon(Icons.copy),
              title: const Text('Copy text'),
              onTap: onCopy,
            ),
          if (onDelete != null)
            ListTile(
              leading: const Icon(Icons.delete_outline, color: Colors.red),
              title: const Text('Delete', style: TextStyle(color: Colors.red)),
              onTap: onDelete,
            ),
        ],
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Typing indicator
// ---------------------------------------------------------------------------

class _TypingIndicator extends ConsumerWidget {
  const _TypingIndicator({required this.roomId});

  final String roomId;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final client = ref.watch(matrixClientProvider);
    final room = client.getRoomById(roomId);
    if (room == null) return const SizedBox.shrink();

    // typingUsers returns Users currently typing (excluding self).
    final typing = room.typingUsers
        .where((u) => u.id != client.userID)
        .map((u) => u.displayName ?? u.id.matrixLocalpart)
        .toList();

    if (typing.isEmpty) return const SizedBox(height: 4);

    final label = typing.length == 1
        ? '${typing.first} is typing…'
        : '${typing.take(2).join(', ')} are typing…';

    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
      child: Row(
        children: [
          Text(
            label,
            style: Theme.of(context).textTheme.bodySmall?.copyWith(
              color: Theme.of(context).colorScheme.onSurface.withAlpha(153),
              fontStyle: FontStyle.italic,
            ),
          ),
        ],
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Input wrapper
// ---------------------------------------------------------------------------

class _Input extends ConsumerWidget {
  const _Input({
    required this.roomId,
    this.replyToEventId,
    this.replyToSenderName,
    this.replyToBody,
    this.onCancelReply,
  });

  final String roomId;
  final String? replyToEventId;
  final String? replyToSenderName;
  final String? replyToBody;
  final VoidCallback? onCancelReply;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isSending = ref.watch(sendMessageProvider);
    final uploadState = ref.watch(uploadFileProvider);
    final isUploading = uploadState == '';

    return MessageInput(
      isSending: isSending || isUploading,
      replyTo: (replyToEventId != null && replyToSenderName != null)
          ? ReplyTo(
              eventId: replyToEventId!,
              senderDisplayName: replyToSenderName!,
              body: replyToBody ?? '',
            )
          : null,
      onCancelReply: onCancelReply,
      onSend: (text) async {
        final error = await ref
            .read(sendMessageProvider.notifier)
            .send(roomId, text, inReplyToEventId: replyToEventId);
        onCancelReply?.call();
        if (error != null && context.mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text('Failed to send: $error'),
              backgroundColor: Theme.of(context).colorScheme.error,
            ),
          );
        }
      },
      onAttach: (MatrixFile file) async {
        await ref.read(uploadFileProvider.notifier).upload(roomId, file);
        final err = ref.read(uploadFileProvider);
        if (err != null && err.isNotEmpty && context.mounted) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text('Upload failed: $err'),
              backgroundColor: Theme.of(context).colorScheme.error,
            ),
          );
          ref.read(uploadFileProvider.notifier).clearError();
        }
      },
    );
  }
}
