import 'dart:async';

import 'package:flutter/material.dart';

import '../../../api/errors/error_mapper.dart';
import '../../../api/marianumcloud/talk/room/get_room_response.dart';
import '../../../api/marianumconnect/queries/user_search/user_search.dart';
import '../../../api/marianumconnect/queries/user_search/user_search_response.dart';
import '../../../widget/app_progress_indicator.dart';
import 'widgets/chat_tile.dart';
import 'widgets/user_search_tile.dart';

class SearchChat extends SearchDelegate<GetRoomResponseObject?> {
  List<GetRoomResponseObject> chats;
  final void Function(GetRoomResponseObject room)? onTapOverride;

  /// When set, results are extended with a clearly separated "start a new chat"
  /// section fed by the MarianumConnect user search. Tapping a person invokes
  /// this callback with their username and display name. Left null (e.g. the
  /// share picker) the search stays limited to existing chats.
  final void Function(String username, String displayName)? onStartChat;

  SearchChat(this.chats, {this.onTapOverride, this.onStartChat});

  @override
  List<Widget>? buildActions(BuildContext context) => [
    if (query.isNotEmpty)
      IconButton(
        tooltip: 'Leeren',
        onPressed: () => query = '',
        icon: const Icon(Icons.clear),
      ),
  ];

  @override
  Widget? buildLeading(BuildContext context) => null;

  @override
  Widget buildResults(BuildContext context) => _SearchChatResults(
    chats: chats,
    query: query,
    onTapOverride: onTapOverride,
    onStartChat: onStartChat == null
        ? null
        : (username, displayName) {
            close(context, null);
            onStartChat!(username, displayName);
          },
  );

  @override
  Widget buildSuggestions(BuildContext context) => buildResults(context);
}

class _SearchChatResults extends StatefulWidget {
  final List<GetRoomResponseObject> chats;
  final String query;
  final void Function(GetRoomResponseObject room)? onTapOverride;
  final void Function(String username, String displayName)? onStartChat;

  const _SearchChatResults({
    required this.chats,
    required this.query,
    required this.onTapOverride,
    required this.onStartChat,
  });

  @override
  State<_SearchChatResults> createState() => _SearchChatResultsState();
}

class _SearchChatResultsState extends State<_SearchChatResults> {
  static const _debounceDelay = Duration(milliseconds: 350);
  static const _minQueryLength = 2;
  static const _loadingIndicator = Padding(
    padding: EdgeInsets.all(16),
    child: Center(child: AppProgressIndicator.medium()),
  );

  Timer? _debounce;

  // Monotonic id so a slow response for an earlier query can never overwrite
  // the results of a newer one.
  int _requestId = 0;

  // null until the first response for the current query settles; previous
  // results stay put while the next query is loading, so the list does not
  // flash to a spinner on every keystroke.
  List<McUserSearchResult>? _users;
  Object? _error;

  @override
  void initState() {
    super.initState();
    _scheduleUserSearch(widget.query);
  }

  @override
  void didUpdateWidget(_SearchChatResults oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.query != widget.query) _scheduleUserSearch(widget.query);
  }

  @override
  void dispose() {
    _debounce?.cancel();
    super.dispose();
  }

  void _scheduleUserSearch(String query) {
    if (widget.onStartChat == null) return;
    _debounce?.cancel();
    final trimmed = query.trim();
    if (trimmed.length < _minQueryLength) {
      // Invalidate any in-flight response and drop the section content.
      _requestId++;
      setState(() {
        _users = null;
        _error = null;
      });
      return;
    }
    _debounce = Timer(_debounceDelay, () => _runSearch(trimmed));
  }

  Future<void> _runSearch(String query) async {
    final id = ++_requestId;
    try {
      final response = await UserSearch().run(query);
      if (!mounted || id != _requestId) return;
      setState(() {
        _users = response.result;
        _error = null;
      });
    } catch (e) {
      if (!mounted || id != _requestId) return;
      setState(() => _error = e);
    }
  }

  @override
  Widget build(BuildContext context) {
    final query = widget.query.toLowerCase();
    final chatMatches =
        widget.chats
            .where(
              (e) =>
                  e.displayName.toString().toLowerCase().contains(query) ||
                  e.name.toString().toLowerCase().contains(query),
            )
            .toList()
          ..sort((a, b) => b.lastActivity.compareTo(a.lastActivity));

    return ListView(
      children: [
        ...chatMatches.map(
          (item) => ChatTile(
            data: item,
            disableContextActions: true,
            onTapOverride: widget.onTapOverride,
          ),
        ),
        if (widget.onStartChat != null) _buildUserSection(context),
      ],
    );
  }

  Widget _buildUserSection(BuildContext context) {
    if (widget.query.trim().length < _minQueryLength) {
      return const SizedBox.shrink();
    }
    // Usernames that already have a direct chat — they are listed above, so
    // the "start new chat" section skips them.
    final existing = <String>{
      for (final c in widget.chats)
        if (c.type == GetRoomResponseObjectConversationType.oneToOne) c.name,
    };
    final theme = Theme.of(context);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        const Divider(height: 32),
        Padding(
          padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
          child: Row(
            children: [
              Icon(
                Icons.person_add_alt_1,
                size: 20,
                color: theme.colorScheme.primary,
              ),
              const SizedBox(width: 10),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Neuen Chat starten',
                      style: theme.textTheme.titleSmall?.copyWith(
                        fontWeight: FontWeight.w600,
                      ),
                    ),
                    Text(
                      'Personen aus der Suche',
                      style: theme.textTheme.bodySmall?.copyWith(
                        color: theme.hintColor,
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
        _buildUserResults(context, existing),
      ],
    );
  }

  Widget _buildUserResults(BuildContext context, Set<String> existing) {
    if (_error != null) return _hint(context, errorToUserMessage(_error));
    final all = _users;
    if (all == null) return _loadingIndicator;
    final users = all.where((u) => !existing.contains(u.username)).toList();
    if (users.isEmpty) {
      return _hint(context, 'Keine weiteren Personen gefunden');
    }
    return Column(
      children: users
          .map(
            (user) => UserSearchTile(
              user: user,
              onTap: () => widget.onStartChat!(
                user.username,
                '${user.firstName} ${user.lastName}',
              ),
            ),
          )
          .toList(),
    );
  }

  Widget _hint(BuildContext context, String text) {
    final theme = Theme.of(context);
    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
      child: Text(
        text,
        style: theme.textTheme.bodyMedium?.copyWith(color: theme.hintColor),
      ),
    );
  }
}
