import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:whitenoise/hooks/use_chat_list.dart';
import 'package:whitenoise/hooks/use_chat_list_search.dart';
import 'package:whitenoise/hooks/use_system_notice.dart';
import 'package:whitenoise/hooks/use_zapstore_update.dart';
import 'package:whitenoise/l10n/l10n.dart';
import 'package:whitenoise/providers/account_pubkey_provider.dart';
import 'package:whitenoise/providers/offline_provider.dart';
import 'package:whitenoise/routes.dart';
import 'package:whitenoise/theme.dart';
import 'package:whitenoise/utils/chat_search.dart';
import 'package:whitenoise/widgets/chat_list_filters.dart';
import 'package:whitenoise/widgets/chat_list_header.dart';
import 'package:whitenoise/widgets/chat_list_search_and_filters.dart';
import 'package:whitenoise/widgets/chat_list_tile.dart';
import 'package:whitenoise/widgets/offline_system_notice.dart';
import 'package:whitenoise/widgets/wn_button.dart';
import 'package:whitenoise/widgets/wn_chat_list.dart';
import 'package:whitenoise/widgets/wn_icon.dart';
import 'package:whitenoise/widgets/wn_search_field.dart';
import 'package:whitenoise/widgets/wn_slate.dart';
import 'package:whitenoise/widgets/wn_system_notice.dart';

const _zapstoreUrl = 'https://zapstore.dev/apps/org.parres.whitenoise';

const _slateHeight = 80;
const _filterChipsHeight = 40;

enum ChatListFilter { chats, archive }

class ChatListScreen extends HookConsumerWidget {
  const ChatListScreen({super.key});

  Widget _buildWelcomeDescription(
    BuildContext context,
    AppTypography typography,
    SemanticColors colors,
  ) {
    final l10n = context.l10n;
    final baseStyle = typography.medium14.copyWith(
      color: colors.backgroundContentQuaternary,
    );
    final highlightStyle = typography.medium14.copyWith(
      color: colors.backgroundContentPrimary,
    );

    final findPeople = l10n.findPeople;
    final shareProfile = l10n.shareYourProfile;
    final startNewChat = l10n.startANewChat;

    final template = l10n.welcomeNoticeDescription(
      findPeople,
      shareProfile,
      startNewChat,
    );

    final spans = <InlineSpan>[];
    var currentIndex = 0;

    void addHighlightedText(String text) {
      final index = template.indexOf(text, currentIndex);
      if (index == -1) return;

      if (index > currentIndex) {
        spans.add(TextSpan(text: template.substring(currentIndex, index)));
      }
      spans.add(TextSpan(text: text, style: highlightStyle));
      currentIndex = index + text.length;
    }

    final highlights = [findPeople, shareProfile, startNewChat];
    final sortedHighlights = highlights.toList()
      ..sort((a, b) => template.indexOf(a).compareTo(template.indexOf(b)));

    for (final highlight in sortedHighlights) {
      addHighlightedText(highlight);
    }

    if (currentIndex < template.length) {
      spans.add(TextSpan(text: template.substring(currentIndex)));
    }

    return Text.rich(
      TextSpan(style: baseStyle, children: spans),
    );
  }

  Widget? _buildSystemNotice(
    BuildContext context,
    AppTypography typography,
    SemanticColors colors, {
    required bool isOffline,
    required bool showWelcomeNotice,
    required String? updateVersion,
    required VoidCallback onUpdateDismiss,
    required VoidCallback onWelcomeDismiss,
    required String? noticeMessage,
    required WnSystemNoticeType noticeType,
    required VoidCallback onNoticeDismiss,
  }) {
    if (isOffline) {
      return const OfflineSystemNotice();
    }
    if (noticeMessage != null) {
      return WnSystemNotice(
        key: ValueKey(noticeMessage),
        title: noticeMessage,
        type: noticeType,
        onDismiss: onNoticeDismiss,
      );
    }
    if (updateVersion != null) {
      return WnSystemNotice(
        key: ValueKey('update_notice_$updateVersion'),
        title: context.l10n.updateAvailableTitle,
        description: Text(
          context.l10n.updateAvailableDescription(updateVersion),
          style: typography.medium12.copyWith(
            color: colors.intentionInfoContent,
          ),
        ),
        type: WnSystemNoticeType.info,
        variant: WnSystemNoticeVariant.dismissible,
        onDismiss: onUpdateDismiss,
        primaryAction: WnButton(
          key: const Key('update_now_button'),
          text: context.l10n.updateNow,
          size: WnButtonSize.medium,
          onPressed: () async {
            final launched = await launchUrl(
              Uri.parse(_zapstoreUrl),
              mode: LaunchMode.externalApplication,
            );
            if (!launched && context.mounted) {
              await launchUrl(
                Uri.parse(_zapstoreUrl),
              );
            }
          },
        ),
      );
    }

    if (showWelcomeNotice) {
      return WnSystemNotice(
        key: const Key('welcome_notice'),
        title: context.l10n.welcomeNoticeTitle,
        description: _buildWelcomeDescription(context, typography, colors),
        type: WnSystemNoticeType.neutral,
        variant: WnSystemNoticeVariant.dismissible,
        animateEntrance: false,
        onDismiss: onWelcomeDismiss,
        secondaryAction: WnButton(
          key: const Key('find_people_button'),
          text: context.l10n.findPeople,
          type: WnButtonType.outline,
          size: WnButtonSize.medium,
          trailingIcon: WnIcons.search,
          onPressed: () => Routes.pushToUserSearch(context),
        ),
        primaryAction: WnButton(
          key: const Key('share_profile_button'),
          text: context.l10n.shareYourProfile,
          size: WnButtonSize.medium,
          trailingIcon: WnIcons.qrCode,
          onPressed: () => Routes.pushToShareProfile(context),
        ),
      );
    }

    return null;
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final colors = context.colors;
    final isOffline = ref.watch(offlineProvider).value ?? false;
    final typography = context.typographyScaled;
    final pubkey = ref.watch(accountPubkeyProvider);
    final chatListResult = useChatList(pubkey);
    final archivedChatListResult = useChatList(
      pubkey,
      archived: true,
    );
    final selectedFilter = useState(ChatListFilter.chats);
    final safeAreaTop = MediaQuery.of(context).padding.top;
    final notice = useSystemNotice();
    final updateState = useZapstoreUpdate();
    final searchQuery = useState('');
    final headerOpen = useState(false);
    final welcomeNoticeDismissed = useState(false);
    final chatListTopPadding = useMemoized(() => ValueNotifier(safeAreaTop + _slateHeight.h));
    final chatListSearch = useChatListSearch(
      pubkey: pubkey,
      query: searchQuery.value,
      hiddenPubkeys: chatListResult.blockedPubkeys,
    );

    useEffect(() {
      welcomeNoticeDismissed.value = false;
      return null;
    }, [pubkey]);

    final isArchiveView = selectedFilter.value == ChatListFilter.archive;
    final searchFieldH = WnSearchField.heightOf(context);
    final archiveHeaderH = 16.h + searchFieldH;
    final chatsHeaderH = archiveHeaderH + 8.h + 32.h;
    final activeChatList = isArchiveView ? archivedChatListResult.chats : chatListResult.chats;
    final filteredChats = filterChatsBySearchWithMessageMatches(
      activeChatList,
      searchQuery.value,
      chatListSearch.matchedGroupIds,
    );
    final isLoading = isArchiveView ? archivedChatListResult.isLoading : chatListResult.isLoading;
    final isEmpty = activeChatList.isEmpty && !isLoading;
    final showWelcomeNotice = !isArchiveView && isEmpty && !welcomeNoticeDismissed.value;
    final activeUpdateVersion = updateState.isDismissed ? null : updateState.availableVersion;

    final isSearchVisible = headerOpen.value || searchQuery.value.isNotEmpty;

    return PopScope(
      canPop: !isSearchVisible,
      onPopInvokedWithResult: (didPop, _) {
        if (didPop) return;
        FocusScope.of(context).unfocus();
        searchQuery.value = '';
        headerOpen.value = false;
      },
      child: Scaffold(
        backgroundColor: colors.backgroundPrimary,
        body: Stack(
          children: [
            ValueListenableBuilder<double>(
              valueListenable: chatListTopPadding,
              builder: (context, topPadding, _) => WnChatList(
                itemCount: filteredChats.length,
                isLoading: isLoading,
                isSearchActive: searchQuery.value.isNotEmpty,
                topPadding: topPadding,
                headerOpenNotifier: headerOpen,
                header: ChatListSearchAndFilters(
                  onSearchChanged: (value) => searchQuery.value = value,
                  isLoading: chatListSearch.isSearching,
                  showFilterChips: !isArchiveView,
                  isChatsSelected: !isArchiveView,
                  onChatsSelected: (_) => selectedFilter.value = ChatListFilter.chats,
                  onArchiveSelected: (_) => selectedFilter.value = ChatListFilter.archive,
                ),
                headerHeight: isArchiveView ? archiveHeaderH : chatsHeaderH,
                pinnedHeader: isArchiveView
                    ? Padding(
                        padding: EdgeInsets.only(top: 8.h),
                        child: ChatListFilters(
                          isChatsSelected: selectedFilter.value == ChatListFilter.chats,
                          isArchiveSelected: selectedFilter.value == ChatListFilter.archive,
                          onChatsSelected: (_) => selectedFilter.value = ChatListFilter.chats,
                          onArchiveSelected: (_) {},
                        ),
                      )
                    : null,
                pinnedHeaderHeight: isArchiveView ? _filterChipsHeight.h : 0,
                pinnedHeaderMinOffset: isArchiveView ? 8.h : 0,
                emptyStateContent: isEmpty
                    ? isArchiveView
                          ? Center(
                              key: const Key('archived_chats_empty'),
                              child: Text(
                                context.l10n.archivedChatsEmpty,
                                style: typography.medium14.copyWith(
                                  color: colors.backgroundContentQuaternary,
                                ),
                              ),
                            )
                          : Padding(
                              padding: EdgeInsets.symmetric(horizontal: 40.w),
                              child: Text(
                                key: const Key('welcome_slogan'),
                                context.l10n.sloganFull,
                                style: typography.medium16.copyWith(
                                  color: colors.backgroundContentTertiary,
                                ),
                                textAlign: TextAlign.center,
                              ),
                            )
                    : null,
                itemBuilder: (context, index) {
                  final chatSummary = filteredChats[index];
                  return ChatListTile(
                    key: Key(chatSummary.mlsGroupId),
                    chatSummary: chatSummary,
                    isArchived: isArchiveView,
                    searchSnippet: chatListSearch.messageSnippets[chatSummary.mlsGroupId],
                    onChatListChanged: isArchiveView
                        ? archivedChatListResult.refresh
                        : chatListResult.refresh,
                    onError: notice.showErrorNotice,
                  );
                },
              ),
            ),
            _MeasuredSlate(
              onHeightChanged: (height) {
                if (chatListTopPadding.value != height) {
                  chatListTopPadding.value = height;
                }
              },
              child: SafeArea(
                bottom: false,
                child: WnSlate(
                  systemNotice: _buildSystemNotice(
                    context,
                    typography,
                    colors,
                    showWelcomeNotice: showWelcomeNotice,
                    isOffline: isOffline,
                    updateVersion: activeUpdateVersion,
                    onUpdateDismiss: updateState.dismiss,
                    onWelcomeDismiss: () {
                      if (context.mounted) {
                        welcomeNoticeDismissed.value = true;
                      }
                    },
                    noticeMessage: notice.noticeMessage,
                    noticeType: notice.noticeType,
                    onNoticeDismiss: notice.dismissNotice,
                  ),
                  header: const ChatListHeader(),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _MeasuredSlate extends StatefulWidget {
  const _MeasuredSlate({
    required this.onHeightChanged,
    required this.child,
  });

  final ValueChanged<double> onHeightChanged;
  final Widget child;

  @override
  State<_MeasuredSlate> createState() => _MeasuredSlateState();
}

class _MeasuredSlateState extends State<_MeasuredSlate> {
  final _key = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return NotificationListener<SizeChangedLayoutNotification>(
      onNotification: (_) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          final box = _key.currentContext?.findRenderObject() as RenderBox?;
          if (box == null || !box.hasSize) return;
          widget.onHeightChanged(box.size.height);
        });
        return false;
      },
      child: SizeChangedLayoutNotifier(
        child: SizedBox(key: _key, child: widget.child),
      ),
    );
  }
}
