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

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;

import '../../../core/network/matrix_client.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 _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 = room?.avatar?.toString();

    return Scaffold(
      appBar: AppBar(
        titleSpacing: 0,
        title: Row(
          children: [
            _RoomAvatarSmall(name: roomName, avatarUrl: roomAvatar),
            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 call
          IconButton(
            icon: const Icon(Icons.videocam_outlined),
            tooltip: 'Video call',
            onPressed: () =>
                context.push('/calls/${Uri.encodeComponent(_decodedRoomId)}'),
          ),
          IconButton(
            icon: const Icon(Icons.more_vert),
            tooltip: 'Room options',
            onPressed: () {},
          ),
        ],
      ),
      body: Column(
        children: [
          Expanded(
            child: _Timeline(roomId: _decodedRoomId, onReply: _setReply),
          ),
          _TypingIndicator(roomId: _decodedRoomId),
          _Input(
            roomId: _decodedRoomId,
            replyToEventId: _replyToEventId,
            replyToSenderName: _replyToSenderName,
            replyToBody: _replyToBody,
            onCancelReply: _clearReply,
          ),
        ],
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// Room avatar
// ---------------------------------------------------------------------------

class _RoomAvatarSmall extends StatelessWidget {
  const _RoomAvatarSmall({required this.name, this.avatarUrl});

  final String name;
  final String? avatarUrl;

  @override
  Widget build(BuildContext context) {
    final initials = name.isNotEmpty ? name[0].toUpperCase() : '?';
    if (avatarUrl != null) {
      return CircleAvatar(
        radius: 18,
        backgroundImage: NetworkImage(avatarUrl!),
      );
    }
    return CircleAvatar(
      radius: 18,
      backgroundColor: Theme.of(context).colorScheme.primary.withAlpha(51),
      child: Text(
        initials,
        style: TextStyle(
          fontSize: 14,
          fontWeight: FontWeight.bold,
          color: Theme.of(context).colorScheme.primary,
        ),
      ),
    );
  }
}

// ---------------------------------------------------------------------------
// 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),
          ),
        ),
      ),
    );
  }
}

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.split(':').first)
        .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();
        }
      },
    );
  }
}
