import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'package:tugas_akhir_supabase/core/theme/app_colors.dart';
import 'package:tugas_akhir_supabase/screens/community/models/group.dart';
import 'package:tugas_akhir_supabase/screens/community/models/group_message.dart';
import 'package:tugas_akhir_supabase/screens/community/models/message.dart';
import 'package:tugas_akhir_supabase/screens/community/services/group_message_service.dart';
import 'package:tugas_akhir_supabase/screens/community/services/group_service.dart';
import 'package:tugas_akhir_supabase/screens/community/services/profile_service.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:intl/intl.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:supabase_flutter/supabase_flutter.dart';

import 'package:tugas_akhir_supabase/screens/community/components/message_item.dart';
import 'package:tugas_akhir_supabase/screens/community/components/message_input.dart';
import 'package:tugas_akhir_supabase/screens/community/components/empty_state.dart';
import 'package:tugas_akhir_supabase/screens/shared/leaf_pattern_painter.dart';

class GroupChatScreen extends StatefulWidget {
  final String groupId;
  final bool isInTabView;
  final GlobalKey<GroupChatScreenState>? screenKey;

  const GroupChatScreen({
    super.key,
    required this.groupId,
    this.isInTabView = false,
    this.screenKey,
  });

  @override
  GroupChatScreenState createState() => GroupChatScreenState();
}

class GroupChatScreenState extends State<GroupChatScreen>
    with WidgetsBindingObserver, AutomaticKeepAliveClientMixin {
  // Services
  final _groupService = GroupService();
  final _messageService = GroupMessageService();
  final _profileService = ProfileService();

  // Controllers
  final _messageController = TextEditingController();
  final _scrollController = ScrollController();
  final _messageFocusNode = FocusNode();
  final _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
  StreamSubscription? _messageStreamSubscription;

  // State variables
  bool _isLoading = true;
  bool _isLoadingMore = false;
  bool _hasMoreMessages = true;
  bool _isUploading = false;
  bool _isReplying = false;
  bool _showEmojiKeyboard = false;
  final bool _isSelectMode = false;

  // Data
  Group? _currentGroup;
  List<GroupMessage> _messages = [];
  GroupMessage? _replyToMessage;
  File? _selectedImage;
  XFile? _selectedImageFile;
  String? _selectedImagePath;
  Set<String> _deletedMessageIds = {};
  final Set<String> _selectedMessageIds = {};

  // User info
  String? _currentUserEmail;
  String? _currentUsername;

  // Track if a refresh is in progress
  bool _isRefreshing = false;

  // Debounced refresh that prevents infinite loops
  void _debouncedRefresh() {
    if (_isRefreshing) {
      print('[DEBUG] Refresh already in progress, skipping');
      return;
    }

    _isRefreshing = true;
    print('[FORCE] Performing debounced refresh');

    // Do a single aggressive refresh
    _loadMessages(forceRefresh: true);

    // Reset flag after some time
    Future.delayed(Duration(seconds: 5), () {
      if (mounted) {
        _isRefreshing = false;
        print('[DEBUG] Refresh cooldown complete');
      }
    });
  }

  @override
  void initState() {
    super.initState();
    _initialize();
  }

  void _initialize() async {
    WidgetsBinding.instance.addObserver(this);
    _messageController.addListener(_updateSendButtonState);
    _scrollController.addListener(_scrollListener);

    // Immediately load messages without waiting for other initialization
    if (mounted) {
      _loadMessages(forceRefresh: true).catchError((e) {
        print('[ERROR] Initial message load failed: $e');
      });
    }

    // Subscribe to real-time message updates
    _setupStreamSubscription();
    _safeSetupMessagesSubscription();

    // Gunakan try-catch untuk menangkap error dan mencegah crash
    try {
      // Set safety timer untuk mencegah loading yang tidak berhenti
      Future.delayed(Duration(seconds: 5), () {
        if (mounted && _isLoading) {
          print('[WARNING] Force completing group chat loading after timeout');
          setState(() => _isLoading = false);
        }
      });

      // Inisialisasi dengan timeout untuk mencegah blocking
      await _profileService.initialize().timeout(
        Duration(seconds: 2),
        onTimeout: () {
          print('[WARNING] Profile service initialization timed out');
          throw TimeoutException('Profile service initialization timed out');
        },
      );

      await _getCurrentUser().timeout(
        Duration(seconds: 2),
        onTimeout: () {
          print('[WARNING] Get current user timed out');
          // Continue anyway
        },
      );

      await _loadGroupDetails().timeout(
        Duration(seconds: 2),
        onTimeout: () {
          print('[WARNING] Load group details timed out');
          // Continue anyway
        },
      );

      await _loadDeletedMessageIds().timeout(
        Duration(seconds: 2),
        onTimeout: () {
          print('[WARNING] Load deleted message IDs timed out');
          // Continue anyway
        },
      );

      // Delay subscription setup to prevent blocking
      Future.delayed(Duration(milliseconds: 800), () {
        if (mounted) {
          _safeSetupMessagesSubscription();
        }
      });
    } catch (e) {
      print('[ERROR] Error in group chat initialization: $e');
      if (mounted) {
        setState(() => _isLoading = false);
      }
    }
  }

  // Set up subscription to real-time message stream
  void _setupStreamSubscription() {
    _messageStreamSubscription?.cancel();
    // Instead of using messageStream, we'll use the onNewMessage callback in setupMessagesSubscription
  }

  @override
  void didUpdateWidget(GroupChatScreen oldWidget) {
    super.didUpdateWidget(oldWidget);
    // If group ID changed, reload everything
    if (oldWidget.groupId != widget.groupId) {
      _loadGroupDetails();
      _loadMessages(forceRefresh: true);
      _setupStreamSubscription();
      _safeSetupMessagesSubscription();
    }
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    _messageController.removeListener(_updateSendButtonState);
    _messageController.dispose();
    _messageFocusNode.dispose();
    _scrollController.removeListener(_scrollListener);
    _scrollController.dispose();
    _messageStreamSubscription?.cancel();

    super.dispose();
  }

  @override
  bool get wantKeepAlive => true;

  // User details
  Future<void> _getCurrentUser() async {
    final userInfo = await _profileService.getCurrentUser();
    if (mounted) {
      setState(() {
        _currentUserEmail = userInfo.email;
        _currentUsername = userInfo.username;
      });
    }
  }

  // Load group details
  Future<void> _loadGroupDetails() async {
    try {
      final group = await _groupService.getGroupDetails(widget.groupId);

      if (mounted && group != null) {
        setState(() {
          _currentGroup = group;
        });
      }
    } catch (e) {
      print('[ERROR] Failed to load group details: $e');
    }
  }

  // Load messages
  Future<void> _loadMessages({
    bool forceRefresh = false,
    bool loadNew = false,
  }) async {
    print(
      '[DEBUG] _loadMessages called. forceRefresh: $forceRefresh, loadNew: $loadNew',
    );
    if (!mounted) return;

    setState(() {
      if (!loadNew) _isLoading = true;
    });

    try {
      final result = await _messageService.loadMessages(
        widget.groupId,
        forceRefresh: forceRefresh,
        loadNew: loadNew,
        existingMessages: _messages,
      );

      if (!mounted) return;

      setState(() {
        // Filter out deleted messages
        List<GroupMessage> filteredMessages =
            result.messages
                .where((msg) => !_deletedMessageIds.contains(msg.id))
                .toList();

        if (loadNew && _messages.isNotEmpty) {
          // Add only new messages that don't already exist
          final existingIds = _messages.map((m) => m.id).toSet();
          final newMessages =
              filteredMessages
                  .where((msg) => !existingIds.contains(msg.id))
                  .toList();

          _messages.insertAll(0, newMessages);

          // Ensure no duplicates and proper sorting
          final uniqueMessages = <String>{};
          _messages =
              _messages.where((msg) {
                final isUnique = !uniqueMessages.contains(msg.id);
                uniqueMessages.add(msg.id);
                return isUnique;
              }).toList();
        } else {
          _messages = filteredMessages;
        }

        // Always sort after modifying the list
        _messages.sort((a, b) => b.createdAt.compareTo(a.createdAt));

        _hasMoreMessages = result.hasMore;
        _isLoading = false;
      });
    } catch (e) {
      if (mounted) {
        setState(() => _isLoading = false);
        _showErrorSnackBar(
          'Gagal memuat pesan. Silakan coba lagi.',
          onRetry: () => _loadMessages(forceRefresh: true),
        );
      }
    }
  }

  Future<void> _loadMoreMessages() async {
    if (!mounted || _isLoadingMore || !_hasMoreMessages) return;

    setState(() => _isLoadingMore = true);

    try {
      final result = await _messageService.loadMoreMessages(
        widget.groupId,
        _messages,
      );

      if (mounted) {
        setState(() {
          // Filter out deleted messages
          List<GroupMessage> filteredMessages =
              result.messages
                  .where((msg) => !_deletedMessageIds.contains(msg.id))
                  .toList();

          // Add only messages that don't already exist
          final existingIds = _messages.map((m) => m.id).toSet();
          final newMessages =
              filteredMessages
                  .where((msg) => !existingIds.contains(msg.id))
                  .toList();

          _messages.addAll(newMessages);

          // Ensure no duplicates
          final uniqueMessages = <String>{};
          _messages =
              _messages.where((msg) {
                final isUnique = !uniqueMessages.contains(msg.id);
                uniqueMessages.add(msg.id);
                return isUnique;
              }).toList();

          // Always sort after modifying the list
          _messages.sort((a, b) => b.createdAt.compareTo(a.createdAt));

          _hasMoreMessages = result.hasMore;
          _isLoadingMore = false;
        });
      }
    } catch (e) {
      if (mounted) {
        setState(() => _isLoadingMore = false);
        _showErrorSnackBar('Gagal memuat pesan sebelumnya. Silakan coba lagi.');
      }
    }
  }

  // Message sending
  Future<void> _sendMessage() async {
    final messageText = _messageController.text.trim();
    if (messageText.isEmpty && _selectedImage == null) return;

    _messageController.clear();
    final imageToUpload = _selectedImage;
    final replyToMessage =
        _replyToMessage != null ? GroupMessage.copy(_replyToMessage!) : null;

    setState(() {
      _selectedImage = null;
      _replyToMessage = null;
      _isReplying = false;
      _isUploading = imageToUpload != null;
    });

    // If we have an image, create a local preview message immediately
    if (imageToUpload != null) {
      final previewMessage = GroupMessage(
        id: 'temp-${DateTime.now().millisecondsSinceEpoch}',
        content: messageText,
        senderEmail: _currentUserEmail ?? '',
        senderUsername: _currentUsername ?? '',
        senderUserId: _messageService.currentUserId ?? '',
        createdAt: DateTime.now(),
        groupId: widget.groupId,
        isLocalImage: true,
        localImageFile: imageToUpload,
      );

      // Add the preview message to the UI immediately
      setState(() {
        _messages.insert(0, previewMessage);
        _messages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
      });
    }

    try {
      // The image will be shown immediately with an optimistic update
      final result = await _messageService.sendMessage(
        groupId: widget.groupId,
        text: messageText,
        imageFile: imageToUpload,
        replyToMessage: replyToMessage,
        currentUsername: _currentUsername,
        currentEmail: _currentUserEmail,
        onOptimisticUpdate: (message) {
          if (mounted) {
            setState(() {
              // If this is an image update, find and replace the temp message
              if (imageToUpload != null) {
                final tempIndex = _messages.indexWhere(
                  (m) => m.isLocalImage && m.localImageFile == imageToUpload,
                );

                if (tempIndex >= 0) {
                  _messages[tempIndex] = message;
                } else {
                  // Check if the message already exists by ID
                  final existingIndex = _messages.indexWhere(
                    (m) => m.id == message.id,
                  );

                  if (existingIndex >= 0) {
                    // Update existing message (for image URL updates)
                    _messages[existingIndex] = message;
                  } else {
                    // Add new message
                    _messages.insert(0, message);
                  }
                }
              } else {
                // For text messages, just add or update
                final existingIndex = _messages.indexWhere(
                  (m) => m.id == message.id,
                );

                if (existingIndex >= 0) {
                  _messages[existingIndex] = message;
                } else {
                  _messages.insert(0, message);
                }
              }

              // Remove duplicates and sort
              final uniqueIds = <String>{};
              _messages =
                  _messages.where((msg) {
                    final isUnique = !uniqueIds.contains(msg.id);
                    uniqueIds.add(msg.id);
                    return isUnique;
                  }).toList();

              _messages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
            });
          }
        },
      );

      // Message was sent successfully
      // The optimistic update already handled UI updates

      // If the message had an image, make sure we have the final version with the correct URL
      if (imageToUpload != null) {
        setState(() {
          _isUploading = false;
        });
      }
    } catch (e) {
      if (mounted) {
        setState(() => _isUploading = false);
        _showErrorSnackBar(
          'Pesan gagal terkirim. Coba lagi nanti.',
          onRetry: () => _sendMessage(),
        );
      }
    }
  }

  // Read status
  void _markVisibleMessagesAsRead() {
    _messageService.markMessagesAsRead(_messages);
  }

  void _updateReadStatus() {
    _markVisibleMessagesAsRead();
  }

  // New message handler
  void _onNewMessage(GroupMessage message) {
    if (!mounted) return;

    // Check if we already have this message
    final existingIndex = _messages.indexWhere((m) => m.id == message.id);

    setState(() {
      if (existingIndex >= 0) {
        // Update existing message (e.g., when image URL is updated)
        _messages[existingIndex] = message;
      } else {
        // Check if message is deleted
        if (!_deletedMessageIds.contains(message.id)) {
          // Insert without duplicating
          _messages.insert(0, message);
        }
      }

      // Remove duplicates by ID before sorting
      final uniqueMessages = <String>{};
      _messages =
          _messages.where((msg) {
            final isUnique = !uniqueMessages.contains(msg.id);
            uniqueMessages.add(msg.id);
            return isUnique;
          }).toList();

      // Sort messages
      _messages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
    });
  }

  // Read status update handler
  void _onReadStatusUpdate(String messageId, String userId) {
    if (!mounted) return;
    setState(() {});
  }

  // Scroll handling
  void _scrollListener() {
    // Load more messages when reaching the bottom
    if (_scrollController.position.pixels >=
            _scrollController.position.maxScrollExtent - 500 &&
        !_isLoadingMore &&
        _hasMoreMessages) {
      _loadMoreMessages();
    }

    // Mark visible messages as read
    _markVisibleMessagesAsRead();
  }

  // UI updates
  void _updateSendButtonState() {
    if (mounted) setState(() {});
  }

  // Reply
  void _startReply(Message message) {
    // Convert Message to GroupMessage if needed
    final groupMessage =
        message is GroupMessage
            ? message
            : GroupMessage.fromMessage(message, widget.groupId);

    // Check message age
    final cutoffDate = DateTime.now().subtract(Duration(days: 30));
    if (message.createdAt.isBefore(cutoffDate)) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
            'Tidak dapat membalas pesan yang lebih lama dari 30 hari',
          ),
          backgroundColor: Colors.orange,
        ),
      );
      return;
    }

    try {
      // Give feedback
      HapticFeedback.lightImpact();

      setState(() {
        _replyToMessage = groupMessage;
        _isReplying = true;
        _showEmojiKeyboard = false;
      });

      // Focus the input field after a short delay
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (mounted) {
          Future.delayed(Duration(milliseconds: 100), () {
            if (mounted) FocusScope.of(context).requestFocus(_messageFocusNode);
          });
        }
      });
    } catch (e) {
      print('[ERROR] Error starting reply: $e');
      setState(() {
        _replyToMessage = null;
        _isReplying = false;
      });
    }
  }

  void _cancelReply() {
    setState(() {
      _replyToMessage = null;
      _isReplying = false;
    });
  }

  // Media
  void _showImageSourceOptions() {
    if (kIsWeb) {
      // On web, only show option to pick from gallery since camera is not supported
      _pickImage();
      return;
    }

    showModalBottomSheet(
      context: context,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
      ),
      builder:
          (context) => SafeArea(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                ListTile(
                  leading: Icon(Icons.camera_alt, color: AppColors.primary),
                  title: Text('Camera'),
                  onTap: () {
                    Navigator.pop(context);
                    _pickImageFromCamera();
                  },
                ),
                ListTile(
                  leading: Icon(Icons.photo_library, color: AppColors.primary),
                  title: Text('Gallery'),
                  onTap: () {
                    Navigator.pop(context);
                    _pickImage();
                  },
                ),
              ],
            ),
          ),
    );
  }

  Future<void> _pickImage() async {
    try {
      final ImagePicker picker = ImagePicker();
      final XFile? image = await picker.pickImage(
        source: ImageSource.gallery,
        maxWidth: 1024,
        maxHeight: 1024,
        imageQuality: 85,
      );

      if (image != null && mounted) {
        if (kIsWeb) {
          // For web, we need special handling
          setState(() {
            _selectedImageFile = image;
            _selectedImagePath = 'Image selected';
            _selectedImage = null; // Clear File-based image
          });
        } else {
          // For mobile platforms
          setState(() {
            _selectedImageFile = image;
            _selectedImagePath = image.path;
            _selectedImage = File(image.path);
          });
        }
      }
    } catch (e) {
      print('[ERROR] Failed to pick image: $e');
      if (mounted) {
        ScaffoldMessenger.of(
          context,
        ).showSnackBar(SnackBar(content: Text('Failed to select image: $e')));
      }
    }
  }

  Future<void> _pickImageFromCamera() async {
    final ImagePicker picker = ImagePicker();
    try {
      final XFile? image = await picker.pickImage(
        source: ImageSource.camera,
        maxWidth: 1024,
        maxHeight: 1024,
        imageQuality: 85,
      );

      if (image != null && mounted) {
        setState(() => _selectedImage = File(image.path));
      }
    } catch (e) {
      print('[ERROR] Gagal mengambil gambar dari kamera: $e');
    }
  }

  // Load deleted message IDs from local storage
  Future<void> _loadDeletedMessageIds() async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final deletedIds =
          prefs.getStringList('deleted_message_ids_${widget.groupId}') ?? [];
      setState(() {
        _deletedMessageIds = Set<String>.from(deletedIds);
      });
    } catch (e) {
      print('[ERROR] Failed to load deleted message IDs: $e');
    }
  }

  // Save deleted message IDs to local storage
  Future<void> _saveDeletedMessageIds() async {
    try {
      final prefs = await SharedPreferences.getInstance();
      await prefs.setStringList(
        'deleted_message_ids_${widget.groupId}',
        _deletedMessageIds.toList(),
      );
    } catch (e) {
      print('[ERROR] Failed to save deleted message IDs: $e');
    }
  }

  void _showErrorSnackBar(String message, {VoidCallback? onRetry}) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        backgroundColor: Colors.red,
        duration: Duration(seconds: 3),
        action:
            onRetry != null
                ? SnackBarAction(label: 'Coba Lagi', onPressed: onRetry)
                : null,
      ),
    );
  }

  Future<void> _openLink(LinkableElement link) async {
    final url = Uri.parse(link.url);

    try {
      if (await canLaunchUrl(url)) {
        await launchUrl(url, mode: LaunchMode.externalApplication);
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Tidak dapat membuka: ${link.url}')),
        );
      }
    } catch (e) {
      print('[ERROR] Gagal membuka URL: $e');
      ScaffoldMessenger.of(
        context,
      ).showSnackBar(SnackBar(content: Text('Gagal membuka URL: $e')));
    }
  }

  bool _shouldShowDateHeader(int index) {
    if (index == _messages.length - 1) {
      return true; // Always show for first message (which is last in the list)
    }

    if (index < _messages.length - 1) {
      final currentDate = DateTime(
        _messages[index].createdAt.year,
        _messages[index].createdAt.month,
        _messages[index].createdAt.day,
      );

      final previousDate = DateTime(
        _messages[index + 1].createdAt.year,
        _messages[index + 1].createdAt.month,
        _messages[index + 1].createdAt.day,
      );

      return currentDate != previousDate;
    }

    return false;
  }

  Widget _buildDateHeader(DateTime date) {
    final now = DateTime.now();
    final today = DateTime(now.year, now.month, now.day);
    final yesterday = today.subtract(const Duration(days: 1));
    final messageDate = DateTime(date.year, date.month, date.day);

    String dateText;
    if (messageDate == today) {
      dateText = 'Hari ini';
    } else if (messageDate == yesterday) {
      dateText = 'Kemarin';
    } else {
      dateText = DateFormat('EEEE, d MMMM y', 'id_ID').format(messageDate);
    }

    return Container(
      margin: const EdgeInsets.symmetric(vertical: 16),
      child: Center(
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
          decoration: BoxDecoration(
            color: Colors.grey[300],
            borderRadius: BorderRadius.circular(16),
          ),
          child: Text(
            dateText,
            style: TextStyle(
              fontSize: 12,
              color: Colors.grey[800],
              fontWeight: FontWeight.w500,
            ),
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        // Pastikan keyboard ditutup sebelum kembali
        if (_showEmojiKeyboard) {
          setState(() => _showEmojiKeyboard = false);
        }
        return true;
      },
      child: Scaffold(
        appBar:
            widget.isInTabView
                ? null
                : AppBar(
                  backgroundColor: AppColors.primary,
                  foregroundColor: Colors.white,
                  title:
                      _currentGroup != null
                          ? Text(_currentGroup!.name)
                          : const Text('Diskusi Grup'),
                  elevation: 0,
                ),
        body: Column(
          children: [
            // Messages area
            Expanded(
              child: GestureDetector(
                // Dismiss keyboard when tapping outside of text field
                onTap: () {
                  if (_showEmojiKeyboard) {
                    setState(() => _showEmojiKeyboard = false);
                  }
                },
                child: Stack(
                  children: [
                    // Agriculture-themed background
                    Positioned.fill(
                      child: Container(
                        decoration: BoxDecoration(
                          gradient: LinearGradient(
                            begin: Alignment.topCenter,
                            end: Alignment.bottomCenter,
                            colors: [
                              Colors.green[50]!,
                              Colors.green[100]!.withOpacity(0.3),
                            ],
                          ),
                        ),
                        child: CustomPaint(
                          painter: LeafPatternPainter(),
                          child: Container(),
                        ),
                      ),
                    ),

                    // Messages content
                    RefreshIndicator(
                      key: _refreshIndicatorKey,
                      color: AppColors.primary,
                      onRefresh: () => _loadMessages(forceRefresh: true),
                      child: _buildMessageArea(),
                    ),
                  ],
                ),
              ),
            ),

            // Input area
            _buildMessageInput(),
          ],
        ),
      ),
    );
  }

  Widget _buildMessageArea() {
    if (_isLoading) {
      return Center(
        child: CircularProgressIndicator(
          valueColor: AlwaysStoppedAnimation<Color>(AppColors.primary),
        ),
      );
    } else if (_messages.isEmpty) {
      return EmptyStateWidget(
        onTap: () {
          print('[FORCE] EmptyState onTap triggered');

          // Use the debounced refresh
          _debouncedRefresh();

          // Try to show the RefreshIndicator directly, but only once
          if (_refreshIndicatorKey.currentState != null && !_isRefreshing) {
            _refreshIndicatorKey.currentState!.show();
          }
        },
      );
    } else {
      return _buildMessageList();
    }
  }

  Widget _buildMessageList() {
    return ListView.builder(
      key: PageStorageKey<String>('group_message_list_${widget.groupId}'),
      controller: _scrollController,
      padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 8),
      itemCount: _messages.length + (_isLoadingMore ? 1 : 0),
      reverse: true,
      cacheExtent: 1000, // Keep more items in memory
      addAutomaticKeepAlives: true,
      itemBuilder: (context, index) {
        // Show loading indicator at the end of the list
        if (index == _messages.length) {
          return const Center(
            child: Padding(
              padding: EdgeInsets.symmetric(vertical: 16.0),
              child: CircularProgressIndicator(),
            ),
          );
        }

        final message = _messages[index];
        final isMyMessage =
            message.senderUserId == _messageService.currentUserId;

        // Check if we need to show date header
        final showDateHeader = _shouldShowDateHeader(index);

        // Use a more efficient approach to rebuild only when needed
        return Column(
          children: [
            if (showDateHeader) _buildDateHeader(_messages[index].createdAt),
            MessageItem(
              key: ValueKey<String>(message.id),
              message: message,
              isMyMessage: isMyMessage,
              isReadByAll: _messageService.isMessageReadByAll(message),
              onReply: _startReply,
              onLongPress: _showMessageOptions,
              onOpenLink: (link) => _openLink(link),
            ),
          ],
        );
      },
    );
  }

  void _showMessageOptions(Message message) {
    final bool isMyMessage =
        message.senderUserId == _messageService.currentUserId;

    showModalBottomSheet(
      context: context,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
      ),
      builder:
          (context) => SafeArea(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                ListTile(
                  leading: Icon(Icons.reply, color: Colors.green.shade700),
                  title: const Text('Balas'),
                  onTap: () {
                    Navigator.pop(context);
                    _startReply(message);
                  },
                ),
                // Only show delete options for user's own messages
                if (isMyMessage)
                  ListTile(
                    leading: Icon(Icons.delete_forever, color: Colors.red),
                    title: const Text('Hapus untuk semua orang'),
                    onTap: () {
                      Navigator.pop(context);
                      _showDeleteConfirmation(message);
                    },
                  ),
              ],
            ),
          ),
    );
  }

  void _showDeleteConfirmation(Message message) {
    showDialog(
      context: context,
      builder:
          (context) => AlertDialog(
            title: Text('Konfirmasi Hapus'),
            content: Text(
              'Pesan ini akan dihapus untuk semua orang. Lanjutkan?',
            ),
            actions: [
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: Text('Batal'),
              ),
              TextButton(
                style: TextButton.styleFrom(foregroundColor: Colors.red),
                onPressed: () {
                  Navigator.pop(context);
                  _deleteMessage(message);
                },
                child: Text('Hapus'),
              ),
            ],
          ),
    );
  }

  Future<void> _deleteMessage(Message message) async {
    // First remove from local list for immediate feedback
    setState(() {
      _messages.removeWhere((m) => m.id == message.id);
      _deletedMessageIds.add(message.id);
    });

    _saveDeletedMessageIds();

    try {
      // Convert to GroupMessage if needed
      final groupMessage =
          message is GroupMessage
              ? message
              : GroupMessage.fromMessage(message, widget.groupId);

      await _messageService.deleteMessage(groupMessage);

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Pesan dihapus'),
          backgroundColor: Colors.green,
          duration: Duration(seconds: 2),
        ),
      );
    } catch (e) {
      print('[ERROR] Failed to delete message: $e');

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Gagal menghapus pesan dari server: $e'),
          backgroundColor: Colors.red,
        ),
      );
    }
  }

  Widget _buildMessageInput() {
    return MessageInputWidget(
      messageController: _messageController,
      focusNode: _messageFocusNode,
      isUploading: _isUploading,
      selectedImage: _selectedImage,
      showEmojiKeyboard: _showEmojiKeyboard,
      isReplying: _isReplying,
      replyToMessage: _replyToMessage,
      onSend: _sendMessage,
      onImageOptions: _showImageSourceOptions,
      themeColor: AppColors.primary,
      onEmojiToggle: () {
        setState(() {
          _showEmojiKeyboard = !_showEmojiKeyboard;
          if (_showEmojiKeyboard) {
            _messageFocusNode.unfocus();
          } else {
            _messageFocusNode.requestFocus();
          }
        });
      },
      onClearImage: () {
        setState(() => _selectedImage = null);
      },
      onCancelReply: _cancelReply,
    );
  }

  // Public method to force refresh
  void forceRefresh() {
    print('[DEBUG] Force refresh called on GroupChatScreen');

    // Make sure we're not already refreshing
    if (_isLoading) {
      print('[DEBUG] Already loading, skipping additional refresh');
      return;
    }

    // Aggressively load messages with forceRefresh
    _loadMessages(forceRefresh: true);

    // Additional refresh after a short delay for images
    Future.delayed(Duration(milliseconds: 500), () {
      if (mounted) {
        setState(() {
          // Force UI update even if data hasn't changed
          // This ensures image cache is properly refreshed
        });
      }
    });
  }

  // Emergency direct database access to bypass service layer
  void _emergencyLoadMessages() async {
    try {
      print(
        '[FORCE] Emergency direct message load for group: ${widget.groupId}',
      );
      final supabase = Supabase.instance.client;

      // Try to load directly from database
      final response = await supabase
          .from('messages_with_sender')
          .select()
          .eq('group_id', widget.groupId)
          .order('created_at', ascending: false)
          .limit(20);

      print('[FORCE] Got ${response.length} messages directly from database');

      if (mounted && response.isNotEmpty) {
        // Process messages
        final messages =
            response.map((data) {
              return GroupMessage.fromMap({
                'id': data['id'],
                'content': data['content'] ?? '',
                'sender_user_id': data['sender_user_id'] ?? '',
                'sender_username':
                    data['profile_username'] ?? data['sender_username'] ?? '',
                'sender_email':
                    data['profile_email'] ?? data['sender_email'] ?? '',
                'created_at': data['created_at'],
                'image_url': data['image_url'],
                'reply_to_id': data['reply_to_id'],
                'reply_to_content': data['reply_to_content'],
                'reply_to_sender_email': data['reply_to_sender_email'],
                'avatar_url': data['avatar_url'],
                'group_id': data['group_id'],
              });
            }).toList();

        // Update UI with messages
        setState(() {
          if (_messages.isEmpty) {
            _messages = messages.toList();
            _messages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
          }
          _isLoading = false;
        });
      }
    } catch (e) {
      print('[ERROR] Emergency load failed: $e');
    }
  }

  // Set up message subscriptions safely with timeout
  void _safeSetupMessagesSubscription() {
    print('[DEBUG] _safeSetupMessagesSubscription called');
    try {
      // Set up real-time message subscription with timeout
      _messageService.setupMessagesSubscription(
        widget.groupId,
        _onNewMessage,
        _onReadStatusUpdate,
      );

      // Also set up the stream listener
      _setupStreamSubscription();

      // Mark messages as read on initial load
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _markVisibleMessagesAsRead();
      });
    } catch (e) {
      print('[ERROR] Error setting up message subscription: $e');
    }
  }

  // Set up real time subscription explicitly
  void setupRealTimeSubscription() {
    print('[STREAM] Setting up real-time subscription from parent call');
    _safeSetupMessagesSubscription();
    _setupStreamSubscription();
  }

  // Clean up resources explicitly when called from parent
  void disposeResources() {
    print('[STREAM] Cleaning up resources from parent call');
    _messageStreamSubscription?.cancel();
  }

  // Set preloaded messages directly from the parent component
  void setPreloadedMessages(List<dynamic> messageData) {
    if (!mounted) return;

    try {
      print('[DIRECT] Setting ${messageData.length} preloaded messages');

      final messages =
          messageData.map((data) {
            return GroupMessage.fromMap({
              'id': data['id'],
              'content': data['content'] ?? '',
              'sender_user_id': data['sender_user_id'] ?? '',
              'sender_username':
                  data['profile_username'] ?? data['sender_username'] ?? '',
              'sender_email':
                  data['profile_email'] ?? data['sender_email'] ?? '',
              'created_at': data['created_at'],
              'image_url': data['image_url'],
              'reply_to_id': data['reply_to_id'],
              'reply_to_content': data['reply_to_content'],
              'reply_to_sender_email': data['reply_to_sender_email'],
              'avatar_url': data['avatar_url'],
              'group_id': data['group_id'],
            });
          }).toList();

      setState(() {
        if (_messages.isEmpty) {
          _messages = messages.toList();
          _messages.sort((a, b) => b.createdAt.compareTo(a.createdAt));
          _isLoading = false;
          print(
            '[DIRECT] Successfully set ${_messages.length} preloaded messages',
          );
        }
      });
    } catch (e) {
      print('[ERROR] Failed to set preloaded messages: $e');
    }
  }
}
