// Version: 1.0.0 | Created: 2026-04-27
// Public room browser — search Matrix room directory and join rooms.

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix_api_lite.dart'
    show PublicRoomQueryFilter, PublicRoomsChunk;
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../../../core/network/matrix_client.dart';
import '../../../shared/widgets/matrix_avatar.dart';

part 'public_rooms_dialog.g.dart';

@riverpod
Future<List<PublicRoomsChunk>> publicRooms(
    Ref ref, String searchTerm) async {
  final client = ref.watch(matrixClientProvider);
  final filter = searchTerm.trim().isEmpty
      ? null
      : PublicRoomQueryFilter(genericSearchTerm: searchTerm.trim());

  final response = await client.queryPublicRooms(
    filter: filter,
    limit: 30,
  );
  return response.chunk;
}

Future<void> showPublicRoomsDialog(BuildContext context) {
  return showDialog<void>(
    context: context,
    builder: (_) => const _PublicRoomsDialog(),
  );
}

class _PublicRoomsDialog extends ConsumerStatefulWidget {
  const _PublicRoomsDialog();

  @override
  ConsumerState<_PublicRoomsDialog> createState() =>
      _PublicRoomsDialogState();
}

class _PublicRoomsDialogState extends ConsumerState<_PublicRoomsDialog> {
  final _controller = TextEditingController();
  String _searchTerm = '';
  Timer? _debounce;
  String? _joiningRoomId;

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

  void _onSearchChanged(String val) {
    _debounce?.cancel();
    _debounce = Timer(const Duration(milliseconds: 450), () {
      if (mounted) setState(() => _searchTerm = val);
    });
  }

  Future<void> _join(PublicRoomsChunk room) async {
    if (_joiningRoomId != null) return;
    setState(() => _joiningRoomId = room.roomId);

    try {
      final client = ref.read(matrixClientProvider);
      await client.joinRoom(room.canonicalAlias ?? room.roomId);
      if (!mounted) return;
      Navigator.of(context).pop();
      context.push('/rooms/${Uri.encodeComponent(room.roomId)}');
    } on Exception catch (e) {
      if (!mounted) return;
      setState(() => _joiningRoomId = null);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Could not join room: $e')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final roomsAsync = ref.watch(publicRoomsProvider(_searchTerm));

    return Dialog(
      insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 32),
      child: ConstrainedBox(
        constraints: const BoxConstraints(maxWidth: 520, maxHeight: 600),
        child: Column(
          children: [
            // Header
            Padding(
              padding: const EdgeInsets.fromLTRB(16, 16, 4, 0),
              child: Row(
                children: [
                  Text(
                    'Find rooms',
                    style: theme.textTheme.titleMedium?.copyWith(
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  const Spacer(),
                  IconButton(
                    icon: const Icon(Icons.close),
                    onPressed: () => Navigator.of(context).pop(),
                  ),
                ],
              ),
            ),

            // Search
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              child: TextField(
                controller: _controller,
                autofocus: true,
                decoration: const InputDecoration(
                  hintText: 'Search public rooms...',
                  prefixIcon: Icon(Icons.search),
                ),
                onChanged: _onSearchChanged,
              ),
            ),

            // Results
            Flexible(
              child: roomsAsync.when(
                loading: () =>
                    const Center(child: CircularProgressIndicator()),
                error: (err, _) => Padding(
                  padding: const EdgeInsets.all(16),
                  child: Text('Search failed: $err'),
                ),
                data: (rooms) {
                  if (rooms.isEmpty) {
                    return Padding(
                      padding: const EdgeInsets.all(24),
                      child: Text(
                        _searchTerm.isEmpty
                            ? 'No public rooms found.'
                            : 'No rooms match "$_searchTerm".',
                        textAlign: TextAlign.center,
                        style: theme.textTheme.bodySmall?.copyWith(
                          color: theme.colorScheme.onSurface.withAlpha(102),
                        ),
                      ),
                    );
                  }

                  return ListView.separated(
                    shrinkWrap: true,
                    itemCount: rooms.length,
                    separatorBuilder: (_, __) =>
                        const Divider(height: 1, indent: 72),
                    itemBuilder: (context, index) {
                      final room = rooms[index];
                      final name = room.name ??
                          room.canonicalAlias ??
                          room.roomId;
                      final isJoining = _joiningRoomId == room.roomId;

                      return ListTile(
                        leading: MatrixAvatar(
                          name: name,
                          avatarUrl: room.avatarUrl?.toString(),
                          radius: 20,
                        ),
                        title: Text(
                          name,
                          overflow: TextOverflow.ellipsis,
                        ),
                        subtitle: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            if (room.topic != null)
                              Text(
                                room.topic!,
                                maxLines: 1,
                                overflow: TextOverflow.ellipsis,
                                style: theme.textTheme.bodySmall,
                              ),
                            Text(
                              '${room.numJoinedMembers} member'
                              '${room.numJoinedMembers == 1 ? '' : 's'}',
                              style: theme.textTheme.bodySmall?.copyWith(
                                color: theme.colorScheme.onSurface
                                    .withAlpha(120),
                              ),
                            ),
                          ],
                        ),
                        isThreeLine: room.topic != null,
                        trailing: isJoining
                            ? const SizedBox(
                                width: 20,
                                height: 20,
                                child: CircularProgressIndicator(
                                    strokeWidth: 2),
                              )
                            : OutlinedButton(
                                onPressed: _joiningRoomId != null
                                    ? null
                                    : () => _join(room),
                                child: const Text('Join'),
                              ),
                      );
                    },
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}
