part of '../chat_view.dart';

class _TypingIndicator extends StatefulWidget {
  final Room room;
  final PyramidTheme pt;
  const _TypingIndicator({required this.room, required this.pt});

  @override
  State<_TypingIndicator> createState() => _TypingIndicatorState();
}

class _TypingIndicatorState extends State<_TypingIndicator> {
  StreamSubscription? _sub;
  List<User> _typing = [];

  StreamSubscription _listenTyping(Room room) {
    // client.onSync fires after every sync — cheap to filter for typing events.
    return room.client.onSync.stream.listen((_) {
      if (!mounted) return;
      final typing = room.typingUsers
          .where((u) => u.id != room.client.userID)
          .toList();
      if (typing.length != _typing.length ||
          !typing.every((u) => _typing.any((t) => t.id == u.id))) {
        setState(() => _typing = typing);
      }
    });
  }

  @override
  void initState() {
    super.initState();
    _sub = _listenTyping(widget.room);
  }

  @override
  void didUpdateWidget(_TypingIndicator oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.room.id != widget.room.id) {
      _sub?.cancel();
      setState(() => _typing = []);
      _sub = _listenTyping(widget.room);
    }
  }

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

  @override
  Widget build(BuildContext context) {
    if (_typing.isEmpty) return const SizedBox.shrink();
    final pt = widget.pt;
    final names = _typing.map((u) => u.calcDisplayname()).toList();
    final label = names.length == 1
        ? '${names[0]} tippt…'
        : names.length == 2
            ? '${names[0]} und ${names[1]} tippen…'
            : '${names[0]} und ${names.length - 1} weitere tippen…';
    return Padding(
      padding: const EdgeInsets.fromLTRB(20, 2, 20, 0),
      child: Row(
        children: [
          _TypingDots(color: pt.fgDim),
          const SizedBox(width: 8),
          Flexible(
            child: Text(
              label,
              style: TextStyle(color: pt.fgDim, fontSize: 12, fontStyle: FontStyle.italic),
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
          ),
        ],
      ),
    );
  }
}

class _TypingDots extends StatefulWidget {
  final Color color;
  const _TypingDots({required this.color});

  @override
  State<_TypingDots> createState() => _TypingDotsState();
}

class _TypingDotsState extends State<_TypingDots>
    with SingleTickerProviderStateMixin {
  late final AnimationController _ctrl;

  @override
  void initState() {
    super.initState();
    _ctrl = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 900),
    )..repeat();
  }

  @override
  void dispose() {
    _ctrl.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _ctrl,
      builder: (context, child) {
        return Row(
          mainAxisSize: MainAxisSize.min,
          children: List.generate(3, (i) {
            // Each dot peaks at a different phase.
            final phase = ((_ctrl.value * 3) - i).clamp(0.0, 1.0);
            final opacity = (phase < 0.5 ? phase * 2 : (1 - phase) * 2).clamp(0.3, 1.0);
            return Padding(
              padding: const EdgeInsets.symmetric(horizontal: 1),
              child: Opacity(
                opacity: opacity,
                child: Container(
                  width: 4,
                  height: 4,
                  decoration: BoxDecoration(color: widget.color, shape: BoxShape.circle),
                ),
              ),
            );
          }),
        );
      },
    );
  }
}
