import 'dart:io';
import 'dart:math' as math;
import 'dart:ui';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:island/models/chat.dart';
import 'package:island/models/route_item.dart';
import 'package:island/pods/chat/chat_room.dart';
import 'package:island/pods/chat/chat_summary.dart';
import 'package:island/pods/config.dart';
import 'package:island/pods/userinfo.dart';
import 'package:island/route.dart';
import 'package:island/services/responsive.dart';
import 'package:island/widgets/chat_room_widgets.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:relative_time/relative_time.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:island/services/event_bus.dart';
import 'package:url_launcher/url_launcher.dart';

class CommandPattleWidget extends HookConsumerWidget {
  final VoidCallback onDismiss;

  const CommandPattleWidget({super.key, required this.onDismiss});

  static List<SpecialAction> _getSpecialActions(BuildContext context) {
    return [
      SpecialAction(
        name: 'postCompose'.tr(),
        description: 'postComposeDescription'.tr(),
        icon: Symbols.edit,
        action: () {
          eventBus.fire(const ShowComposeSheetEvent());
        },
      ),
      SpecialAction(
        name: 'notifications'.tr(),
        description: 'notificationsDescription'.tr(),
        searchableAliases: ['notifications', 'alert', 'bell'],
        icon: Symbols.notifications,
        action: () {
          eventBus.fire(const ShowNotificationSheetEvent());
        },
      ),
    ];
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final textController = useTextEditingController();
    final focusNode = useFocusNode();
    final searchQuery = useState('');
    final focusedIndex = useState<int?>(null);
    final scrollController = useScrollController();

    final animationController = useAnimationController(
      duration: const Duration(milliseconds: 200),
    );
    final scaleAnimation = useAnimation(
      Tween<double>(begin: 0.8, end: 1.0).animate(
        CurvedAnimation(parent: animationController, curve: Curves.easeOut),
      ),
    );
    final opacityAnimation = useAnimation(
      Tween<double>(begin: 0.0, end: 1.0).animate(
        CurvedAnimation(parent: animationController, curve: Curves.easeOut),
      ),
    );

    useEffect(() {
      focusNode.requestFocus();
      animationController.forward();
      return null;
    }, []);

    useEffect(() {
      void listener() {
        searchQuery.value = textController.text;
        // Reset focused index when search changes
        focusedIndex.value = null;
      }

      textController.addListener(listener);
      return () => textController.removeListener(listener);
    }, [textController]);

    final chatRooms = ref.watch(chatRoomJoinedProvider);

    bool isDesktop() =>
        kIsWeb ||
        (!kIsWeb &&
            (Platform.isWindows || Platform.isLinux || Platform.isMacOS));

    final filteredChats = chatRooms.maybeWhen(
      data: (rooms) {
        if (searchQuery.value.isEmpty) return <SnChatRoom>[];
        return rooms
            .where((room) {
              final title = room.name ?? '';
              final desc = room.description ?? '';
              final query = searchQuery.value.toLowerCase();
              return title.toLowerCase().contains(query) ||
                  desc.toLowerCase().contains(query) ||
                  (room.members?.any(
                        (member) =>
                            member.account.name.contains(query) ||
                            member.account.nick.contains(query),
                      ) ??
                      false);
            })
            .take(5) // Limit to 5 results
            .toList();
      },
      orElse: () => <SnChatRoom>[],
    );

    final filteredRoutes = searchQuery.value.isEmpty
        ? <RouteItem>[]
        : kAvailableRoutes
              .where((route) {
                final query = searchQuery.value.toLowerCase();
                return route.name.toLowerCase().contains(query) ||
                    route.description.toLowerCase().contains(query) ||
                    route.searchableAliases.any(
                      (e) => e.toLowerCase().contains(query),
                    );
              })
              .take(5) // Limit to 5 results
              .toList();

    final filteredSpecialActions = searchQuery.value.isEmpty
        ? <SpecialAction>[]
        : _getSpecialActions(context)
              .where((action) {
                final query = searchQuery.value.toLowerCase();
                return action.name.toLowerCase().contains(query) ||
                    action.description.toLowerCase().contains(query) ||
                    action.searchableAliases.any(
                      (e) => e.toLowerCase().contains(query),
                    );
              })
              .take(5) // Limit to 5 results
              .toList();

    final filteredFallbacks =
        searchQuery.value.isNotEmpty &&
            filteredChats.isEmpty &&
            filteredSpecialActions.isEmpty &&
            filteredRoutes.isEmpty
        ? _getFallbackActions(ref, context, searchQuery.value)
        : <FallbackAction>[];

    // Combine results: fallbacks first, then chats, special actions, routes
    final allResults = [
      ...filteredFallbacks,
      ...filteredChats,
      ...filteredSpecialActions,
      ...filteredRoutes,
    ];

    // Scroll to focused item
    useEffect(() {
      if (focusedIndex.value != null && allResults.isNotEmpty) {
        // Wait for the next frame to ensure ScrollController is attached
        WidgetsBinding.instance.addPostFrameCallback((_) {
          if (scrollController.hasClients) {
            // Estimate item height (ListTile is typically around 72-88 pixels)
            const double estimatedItemHeight = 80.0;
            final double itemTopOffset =
                focusedIndex.value! * estimatedItemHeight;
            final double viewportHeight =
                scrollController.position.viewportDimension;
            final double centeredOffset =
                itemTopOffset -
                (viewportHeight / 2) +
                (estimatedItemHeight / 2);

            // Animate scroll to center the focused item
            scrollController.animateTo(
              centeredOffset.clamp(
                0.0,
                scrollController.position.maxScrollExtent,
              ),
              duration: const Duration(milliseconds: 200),
              curve: Curves.easeOut,
            );
          }
        });
      }
      return null;
    }, [focusedIndex.value]);

    return KeyboardListener(
      focusNode: FocusNode(),
      onKeyEvent: (event) {
        if (event is KeyDownEvent) {
          if (event.logicalKey == LogicalKeyboardKey.escape) {
            onDismiss();
          } else if (isDesktop()) {
            if (event.logicalKey == LogicalKeyboardKey.enter ||
                event.logicalKey == LogicalKeyboardKey.numpadEnter) {
              final item = allResults[focusedIndex.value ?? 0];
              _executeItem(context, ref, item);
            } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
              if (allResults.isNotEmpty) {
                if (focusedIndex.value == null) {
                  focusedIndex.value = 0;
                } else {
                  focusedIndex.value = math.max(0, focusedIndex.value! - 1);
                }
              }
            } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
              if (allResults.isNotEmpty) {
                if (focusedIndex.value == null) {
                  focusedIndex.value = 0;
                } else {
                  focusedIndex.value = math.min(
                    allResults.length - 1,
                    focusedIndex.value! + 1,
                  );
                }
              }
            }
          }
        }
      },
      child: GestureDetector(
        onTap: onDismiss,
        child: BackdropFilter(
          filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
          child: Container(
            color: Colors.black.withOpacity(0.5),
            child: Align(
              alignment: Alignment.topCenter,
              child: Padding(
                padding: EdgeInsets.only(
                  top: MediaQuery.of(context).size.height * 0.2,
                ),
                child: AnimatedBuilder(
                  animation: animationController,
                  builder: (context, child) => Opacity(
                    opacity: opacityAnimation,
                    child: Transform.scale(scale: scaleAnimation, child: child),
                  ),
                  child: GestureDetector(
                    onTap:
                        () {}, // Prevent tap from dismissing when tapping inside
                    child: Container(
                      width: math.max(
                        MediaQuery.of(context).size.width * 0.6,
                        320,
                      ),
                      constraints: const BoxConstraints(
                        maxWidth: 600,
                        maxHeight: 500,
                      ),
                      decoration: BoxDecoration(
                        color: Theme.of(context).colorScheme.surface,
                        borderRadius: BorderRadius.circular(28),
                        boxShadow: [
                          BoxShadow(
                            color: Colors.black.withOpacity(0.3),
                            blurRadius: 10,
                            spreadRadius: 2,
                          ),
                        ],
                      ),
                      child: Material(
                        elevation: 0,
                        color: Theme.of(context).colorScheme.surface,
                        borderRadius: BorderRadius.circular(28),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            SearchBar(
                              controller: textController,
                              focusNode: focusNode,
                              hintText: 'searchChatsAndPages'.tr(),
                              leading: CircleAvatar(
                                child: const Icon(Symbols.keyboard_command_key),
                              ).padding(horizontal: 8),
                              onSubmitted: !isDesktop() && allResults.isNotEmpty
                                  ? (value) => _executeItem(
                                      context,
                                      ref,
                                      allResults[0],
                                    )
                                  : null,
                            ),
                            AnimatedSize(
                              duration: const Duration(milliseconds: 200),
                              curve: Curves.easeOut,
                              child: allResults.isNotEmpty
                                  ? ConstrainedBox(
                                      constraints: const BoxConstraints(
                                        maxHeight: 300,
                                      ),
                                      child: ListView.builder(
                                        padding: EdgeInsets.zero,
                                        controller: scrollController,
                                        shrinkWrap: true,
                                        itemCount: allResults.length,
                                        itemBuilder: (context, index) {
                                          final item = allResults[index];
                                          if (item is SnChatRoom) {
                                            return _ChatRoomSearchResult(
                                              room: item,
                                              isFocused:
                                                  index == focusedIndex.value,
                                              onTap: () => _navigateToChat(
                                                context,
                                                ref,
                                                item,
                                              ),
                                            );
                                          } else if (item is SpecialAction) {
                                            return _SpecialActionSearchResult(
                                              action: item,
                                              isFocused:
                                                  index == focusedIndex.value,
                                              onTap: () {
                                                onDismiss();
                                                item.action();
                                              },
                                            );
                                          } else if (item is RouteItem) {
                                            return _RouteSearchResult(
                                              route: item,
                                              isFocused:
                                                  index == focusedIndex.value,
                                              onTap: () => _navigateToRoute(
                                                context,
                                                ref,
                                                item,
                                              ),
                                            );
                                          } else if (item is FallbackAction) {
                                            return _FallbackSearchResult(
                                              action: item,
                                              isFocused:
                                                  index == focusedIndex.value,
                                              onTap: () {
                                                onDismiss();
                                                item.action();
                                              },
                                            );
                                          }
                                          return const SizedBox.shrink();
                                        },
                                      ),
                                    )
                                  : const SizedBox.shrink(),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

  void _navigateToChat(BuildContext context, WidgetRef ref, SnChatRoom room) {
    onDismiss();
    if (isWideScreen(context)) {
      debugPrint('${room.name}');
      ref
          .read(routerProvider)
          .replaceNamed('chatRoom', pathParameters: {'id': room.id});
    } else {
      ref
          .read(routerProvider)
          .pushNamed('chatRoom', pathParameters: {'id': room.id});
    }
  }

  void _navigateToRoute(BuildContext context, WidgetRef ref, RouteItem route) {
    onDismiss();
    ref.read(routerProvider).go(route.path);
  }

  void _executeItem(BuildContext context, WidgetRef ref, dynamic item) {
    if (item is SnChatRoom) {
      _navigateToChat(context, ref, item);
    } else if (item is SpecialAction) {
      onDismiss();
      item.action();
    } else if (item is RouteItem) {
      _navigateToRoute(context, ref, item);
    } else if (item is FallbackAction) {
      onDismiss();
      item.action();
    }
  }

  static List<FallbackAction> _getFallbackActions(
    WidgetRef ref,
    BuildContext context,
    String query,
  ) {
    final settings = ref.watch(appSettingsProvider);

    final List<FallbackAction> actions = [];

    // Check if query is a URL
    final Uri? uri = Uri.tryParse(query);
    final isValidUrl =
        uri != null && (uri.scheme == 'http' || uri.scheme == 'https');
    final isDomain = RegExp(
      r'^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$',
    ).hasMatch(query);

    if (isValidUrl || isDomain) {
      final finalUri = isDomain ? Uri.parse('https://$query') : uri!;
      actions.add(
        FallbackAction(
          name: 'Open URL',
          description: 'Open ${finalUri.toString()} in browser',
          icon: Symbols.open_in_new,
          action: () async {
            if (await canLaunchUrl(finalUri)) {
              await launchUrl(finalUri, mode: LaunchMode.externalApplication);
            }
          },
        ),
      );
    }

    // Ask the AI
    // Bugged, DO NOT USE
    // actions.add(
    //   FallbackAction(
    //     name: 'Ask the AI',
    //     description: 'Ask "$query" to the AI',
    //     icon: Symbols.bubble_chart,
    //     action: () {
    //       eventBus.fire(ShowThoughtSheetEvent(initialMessage: query));
    //     },
    //   ),
    // );

    // Search the web
    actions.add(
      FallbackAction(
        name: 'Search the web',
        description: 'Search "$query" on the Internet',
        icon: Symbols.search,
        action: () async {
          final searchUri = Uri.parse(
            settings.dashSearchEngine != null
                ? settings.dashSearchEngine!.replaceFirst('%s', query)
                : 'https://www.google.com/search?q=$query',
          );
          if (await canLaunchUrl(searchUri)) {
            await launchUrl(searchUri, mode: LaunchMode.externalApplication);
          }
        },
      ),
    );

    return actions;
  }
}

class FallbackAction {
  final String name;
  final String description;
  final IconData icon;
  final VoidCallback action;
  final List<String> searchableAliases;

  const FallbackAction({
    required this.name,
    required this.description,
    required this.icon,
    required this.action,
    this.searchableAliases = const [],
  });
}

class _RouteSearchResult extends StatelessWidget {
  final RouteItem route;
  final bool isFocused;
  final VoidCallback onTap;

  const _RouteSearchResult({
    required this.route,
    required this.isFocused,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: isFocused
            ? Theme.of(context).colorScheme.surfaceContainerHighest
            : null,
        borderRadius: const BorderRadius.all(Radius.circular(28)),
      ),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
          foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
          child: Icon(route.icon),
        ),
        title: Text(route.name),
        subtitle: Text(route.description),
        onTap: onTap,
      ),
    );
  }
}

class _SpecialActionSearchResult extends StatelessWidget {
  final SpecialAction action;
  final bool isFocused;
  final VoidCallback onTap;

  const _SpecialActionSearchResult({
    required this.action,
    required this.isFocused,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: isFocused
            ? Theme.of(context).colorScheme.surfaceContainerHighest
            : null,
        borderRadius: const BorderRadius.all(Radius.circular(24)),
      ),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Theme.of(context).colorScheme.tertiaryContainer,
          foregroundColor: Theme.of(context).colorScheme.onTertiaryContainer,
          child: Icon(action.icon),
        ),
        title: Text(action.name),
        subtitle: Text(action.description),
        onTap: onTap,
      ),
    );
  }
}

class _FallbackSearchResult extends StatelessWidget {
  final FallbackAction action;
  final bool isFocused;
  final VoidCallback onTap;

  const _FallbackSearchResult({
    required this.action,
    required this.isFocused,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: isFocused
            ? Theme.of(context).colorScheme.surfaceContainerHighest
            : null,
        borderRadius: const BorderRadius.all(Radius.circular(24)),
      ),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Theme.of(context).colorScheme.primaryContainer,
          foregroundColor: Theme.of(context).colorScheme.onPrimaryContainer,
          child: Icon(action.icon),
        ),
        title: Text(action.name),
        subtitle: Text(action.description),
        onTap: onTap,
      ),
    );
  }
}

class _ChatRoomSearchResult extends HookConsumerWidget {
  final SnChatRoom room;
  final bool isFocused;
  final VoidCallback onTap;

  const _ChatRoomSearchResult({
    required this.room,
    required this.isFocused,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final userInfo = ref.watch(userInfoProvider);
    final summary = ref
        .watch(chatSummaryProvider)
        .whenData((summaries) => summaries[room.id]);

    var validMembers = room.members ?? [];
    if (validMembers.isNotEmpty && userInfo.value != null) {
      validMembers = validMembers
          .where((e) => e.accountId != userInfo.value!.id)
          .toList();
    }

    String titleText;
    if (room.type == 1 && room.name == null) {
      if (room.members?.isNotEmpty ?? false) {
        titleText = validMembers.map((e) => e.account.nick).join(', ');
      } else {
        titleText = 'Direct Message';
      }
    } else {
      titleText = room.name ?? '';
    }

    Widget buildSubtitle() {
      return summary.when(
        data: (data) => data == null
            ? (room.type == 1 && room.description == null
                  ? Text(
                      validMembers.map((e) => '@${e.account.name}').join(', '),
                    )
                  : Text(room.description ?? ''))
            : Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  if (data.unreadCount > 0)
                    Text(
                      'unreadMessages'.plural(data.unreadCount),
                      style: Theme.of(context).textTheme.bodySmall?.copyWith(
                        color: Theme.of(context).colorScheme.primary,
                      ),
                    ),
                  if (data.lastMessage == null)
                    room.type == 1 && room.description == null
                        ? Text(
                            validMembers
                                .map((e) => '@${e.account.name}')
                                .join(', '),
                          )
                        : Text(room.description ?? '')
                  else
                    Row(
                      spacing: 4,
                      children: [
                        Badge(
                          label: Text(data.lastMessage!.sender.account.nick),
                          textColor: Theme.of(context).colorScheme.onPrimary,
                          backgroundColor: Theme.of(
                            context,
                          ).colorScheme.primary,
                        ),
                        Expanded(
                          child: Text(
                            (data.lastMessage!.content?.isNotEmpty ?? false)
                                ? data.lastMessage!.content!
                                : 'messageNone'.tr(),
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: Theme.of(context).textTheme.bodySmall,
                          ),
                        ),
                        Align(
                          alignment: Alignment.centerRight,
                          child: Text(
                            RelativeTime(
                              context,
                            ).format(data.lastMessage!.createdAt),
                            style: Theme.of(context).textTheme.bodySmall,
                          ),
                        ),
                      ],
                    ),
                ],
              ),
        loading: () => room.type == 1 && room.description == null
            ? Text(validMembers.map((e) => '@${e.account.name}').join(', '))
            : Text(room.description ?? ''),
        error: (_, _) => room.type == 1 && room.description == null
            ? Text(validMembers.map((e) => '@${e.account.name}').join(', '))
            : Text(room.description ?? ''),
      );
    }

    final isDirect = room.type == 1;

    return Container(
      decoration: BoxDecoration(
        color: isFocused
            ? Theme.of(context).colorScheme.surfaceContainerHighest
            : null,
        borderRadius: const BorderRadius.all(Radius.circular(24)),
      ),
      child: ListTile(
        leading: ChatRoomAvatar(
          room: room,
          isDirect: isDirect,
          summary: summary,
          validMembers: validMembers,
        ),
        title: Text(titleText),
        subtitle: buildSubtitle(),
        onTap: onTap,
      ),
    );
  }
}
