import 'dart:async';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:matrix/matrix.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pyramid/core/settings_prefs.dart';
import 'package:pyramid/core/theme.dart';
import 'package:pyramid/features/chat/attachment_dialog.dart';
import 'package:pyramid/features/chat/emoji_picker.dart';
import 'package:pyramid/features/chat/gif_sticker_picker.dart';
import 'package:pyramid/utils/clipboard_image.dart';

class ChatComposer extends ConsumerStatefulWidget {
  final Room room;
  final Event? replyTo;
  final VoidCallback? onClearReply;
  final VoidCallback? onOpenEmoji;

  const ChatComposer({
    super.key,
    required this.room,
    this.replyTo,
    this.onClearReply,
    this.onOpenEmoji,
  });

  @override
  ConsumerState<ChatComposer> createState() => _ChatComposerState();
}

class _ChatComposerState extends ConsumerState<ChatComposer> {
  final _ctrl = TextEditingController();
  late final FocusNode _focus;
  bool _canSend = false;
  OverlayEntry? _gifOverlay;
  OverlayEntry? _emojiOverlay;
  Timer? _typingTimer;
  bool _isTyping = false;

  @override
  void initState() {
    super.initState();
    _focus = FocusNode(onKeyEvent: _handleKeyEvent);
    _ctrl.addListener(_onTextChanged);
  }

  KeyEventResult _handleKeyEvent(FocusNode node, KeyEvent event) {
    if (event is KeyDownEvent &&
        event.logicalKey == LogicalKeyboardKey.keyV &&
        HardwareKeyboard.instance.isControlPressed) {
      final bytes = getClipboardImageBytes();
      if (bytes != null) {
        _pasteClipboardImage(bytes);
        return KeyEventResult.handled;
      }
    }
    return KeyEventResult.ignored;
  }

  Future<void> _pasteClipboardImage(Uint8List bytes) async {
    final dir = await getTemporaryDirectory();
    final file = File('${dir.path}/paste_${DateTime.now().millisecondsSinceEpoch}.png');
    await file.writeAsBytes(bytes);
    if (!mounted) return;
    await AttachmentDialog.show(context, [file], widget.room, replyTo: widget.replyTo);
    widget.onClearReply?.call();
    file.delete().catchError((_) => file);
  }

  /// Bilder, die die Android-Tastatur einfügt (Gboard-Clipboard-Chip,
  /// GIF-Auswahl der Tastatur etc.) — landen im Anhang-Dialog mit Vorschau.
  Future<void> _handleInsertedContent(KeyboardInsertedContent content) async {
    final bytes = content.data;
    if (bytes == null || bytes.isEmpty) return;
    final ext = content.mimeType.contains('/')
        ? content.mimeType.split('/').last
        : 'png';
    final dir = await getTemporaryDirectory();
    final file = File(
        '${dir.path}/keyboard_${DateTime.now().millisecondsSinceEpoch}.$ext');
    await file.writeAsBytes(bytes);
    if (!mounted) return;
    await AttachmentDialog.show(context, [file], widget.room, replyTo: widget.replyTo);
    widget.onClearReply?.call();
    file.delete().catchError((_) => file);
  }

  void _onTextChanged() {
    final has = _ctrl.text.trim().isNotEmpty;
    if (has != _canSend) setState(() => _canSend = has);
    _updateTyping(has);
  }

  void _updateTyping(bool typing) {
    final sendTyping = ref.read(privacyTypingProvider);
    if (!sendTyping) return;

    if (typing) {
      // Reset the auto-stop timer on every keystroke.
      _typingTimer?.cancel();
      _typingTimer = Timer(const Duration(seconds: 7), () => _sendTyping(false));
      if (!_isTyping) _sendTyping(true);
    } else {
      _typingTimer?.cancel();
      if (_isTyping) _sendTyping(false);
    }
  }

  void _sendTyping(bool typing) {
    _isTyping = typing;
    widget.room
        .setTyping(typing, timeout: typing ? 10000 : null)
        .catchError((_) {});
  }

  @override
  void dispose() {
    _typingTimer?.cancel();
    if (_isTyping) widget.room.setTyping(false).catchError((_) {});
    _gifOverlay?.remove();
    _emojiOverlay?.remove();
    _ctrl.dispose();
    _focus.dispose();
    super.dispose();
  }

  void _toggleGifPicker() {
    if (_gifOverlay != null) {
      _gifOverlay!.remove();
      _gifOverlay = null;
      return;
    }
    
    final platform = Theme.of(context).platform;
    final isMobile = platform == TargetPlatform.android || platform == TargetPlatform.iOS;
    
    if (isMobile) {
      showModalBottomSheet(
        context: context,
        backgroundColor: Colors.transparent,
        isScrollControlled: true,
        builder: (ctx) => Padding(
          padding: EdgeInsets.only(
            bottom: MediaQuery.viewInsetsOf(ctx).bottom,
            top: 40,
          ),
          child: GifStickerPicker(
            room: widget.room,
            onClose: () => Navigator.of(ctx).pop(),
          ),
        ),
      );
      return;
    }

    final box = context.findRenderObject() as RenderBox?;
    final offset = box?.localToGlobal(Offset.zero) ?? Offset.zero;
    final size = box?.size ?? Size.zero;

    _gifOverlay = OverlayEntry(builder: (ctx) {
      final screenSize = MediaQuery.sizeOf(ctx);
      const pickerW = 380.0;
      const pickerH = 460.0;
      final left = (offset.dx + size.width - pickerW).clamp(8.0, screenSize.width - pickerW - 8);
      final top = (offset.dy - pickerH - 8).clamp(8.0, screenSize.height - pickerH - 8);
      return Material(
        type: MaterialType.transparency,
        child: Stack(children: [
          GestureDetector(
            onTap: () { _gifOverlay?.remove(); _gifOverlay = null; },
            behavior: HitTestBehavior.translucent,
            child: const SizedBox.expand(),
          ),
          Positioned(
            left: left,
            top: top,
            child: GifStickerPicker(
              room: widget.room,
              onClose: () { _gifOverlay?.remove(); _gifOverlay = null; },
            ),
          ),
        ]),
      );
    });
    Overlay.of(context).insert(_gifOverlay!);
  }

  void _toggleEmojiPicker() {
    if (_emojiOverlay != null) {
      _emojiOverlay!.remove();
      _emojiOverlay = null;
      return;
    }
    
    final platform = Theme.of(context).platform;
    final isMobile = platform == TargetPlatform.android || platform == TargetPlatform.iOS;

    void onEmojiSelected(String emoji, BuildContext? ctx) {
      final pos = _ctrl.selection.baseOffset;
      final text = _ctrl.text;
      final before = pos < 0 ? text : text.substring(0, pos);
      final after = pos < 0 ? '' : text.substring(pos);
      _ctrl.value = TextEditingValue(
        text: '$before$emoji$after',
        selection: TextSelection.collapsed(
          offset: before.length + emoji.length,
        ),
      );
      if (isMobile && ctx != null) {
        Navigator.of(ctx).pop();
      } else {
        _emojiOverlay?.remove();
        _emojiOverlay = null;
      }
      _focus.requestFocus();
    }

    if (isMobile) {
      showModalBottomSheet(
        context: context,
        backgroundColor: Colors.transparent,
        isScrollControlled: true,
        builder: (ctx) => Padding(
          padding: EdgeInsets.only(
            bottom: MediaQuery.viewInsetsOf(ctx).bottom,
            top: 40,
          ),
          child: EmojiPicker(
            onEmojiSelected: (emoji) => onEmojiSelected(emoji, ctx),
            onClose: () => Navigator.of(ctx).pop(),
          ),
        ),
      );
      return;
    }

    final box = context.findRenderObject() as RenderBox?;
    final offset = box?.localToGlobal(Offset.zero) ?? Offset.zero;
    final size = box?.size ?? Size.zero;

    _emojiOverlay = OverlayEntry(builder: (ctx) {
      final screenSize = MediaQuery.sizeOf(ctx);
      const pickerW = 340.0;
      const pickerH = 380.0;
      final left = (offset.dx + size.width - pickerW).clamp(8.0, screenSize.width - pickerW - 8);
      final top = (offset.dy - pickerH - 8).clamp(8.0, screenSize.height - pickerH - 8);
      return Material(
        type: MaterialType.transparency,
        child: Stack(children: [
          GestureDetector(
            onTap: () { _emojiOverlay?.remove(); _emojiOverlay = null; },
            behavior: HitTestBehavior.translucent,
            child: const SizedBox.expand(),
          ),
          Positioned(
            left: left,
            top: top,
            child: EmojiPicker(
              onEmojiSelected: (emoji) => onEmojiSelected(emoji, null),
              onClose: () { _emojiOverlay?.remove(); _emojiOverlay = null; },
            ),
          ),
        ]),
      );
    });
    Overlay.of(context).insert(_emojiOverlay!);
  }

  Future<void> _pickAttachment() async {
    final result = await FilePicker.platform.pickFiles(allowMultiple: true);
    if (result == null || result.files.isEmpty) return;
    if (!mounted) return;
    final files = result.files
        .where((f) => f.path != null)
        .map((f) => File(f.path!))
        .toList();
    if (files.isEmpty) return;
    await AttachmentDialog.show(context, files, widget.room, replyTo: widget.replyTo);
    widget.onClearReply?.call();
  }

  Future<void> _send() async {
    final text = _ctrl.text.trim();
    if (text.isEmpty) return;
    _ctrl.clear();
    setState(() => _canSend = false);
    // Stop typing indicator immediately before sending.
    _typingTimer?.cancel();
    if (_isTyping) _sendTyping(false);
    await widget.room.sendTextEvent(text, inReplyTo: widget.replyTo);
    widget.onClearReply?.call();
    _focus.requestFocus();
  }

  @override
  Widget build(BuildContext context) {
    final pt = PyramidTheme.of(context);
    final size = MediaQuery.sizeOf(context);
    final isSmall = size.width < 400;
    
    final roomName = widget.room.getLocalizedDisplayname();
    final placeholder = widget.room.isDirectChat
        ? 'Message…'
        : 'Message #$roomName';

    return SafeArea(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          if (widget.replyTo != null)
            _ReplyBar(
              event: widget.replyTo!,
              onClear: widget.onClearReply ?? () {},
              pt: pt,
            ),
          Padding(
            // Bottom inset matches the profile block in the rooms list (8px) so
            // the composer sits flush with it.
            padding: EdgeInsets.fromLTRB(isSmall ? 8 : 16, 0, isSmall ? 8 : 16, 8),
            child: AnimatedContainer(
              duration: const Duration(milliseconds: 180),
              curve: Curves.easeOutCubic,
              // Tuned so the single-line composer is flush with the profile
              // block in the rooms list (~89px on the user's display). Grows for
              // multiline.
              constraints: const BoxConstraints(minHeight: 53),
              decoration: BoxDecoration(
                color: pt.bg2,
                borderRadius: BorderRadius.circular(pt.rBase + 4),
                border: Border.all(
                  color: _focus.hasFocus ? pt.accent : pt.border,
                ),
                boxShadow: _focus.hasFocus
                    ? [BoxShadow(color: pt.accentSoft, blurRadius: 0, spreadRadius: 3)]
                    : null,
              ),
              child: Focus(
                onFocusChange: (_) => setState(() {}),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    // Attach button
                    _ComposerIconBtn(
                      icon: Icons.add_rounded,
                      tooltip: 'Datei anhängen',
                      pt: pt,
                      size: size.width < 600 ? 24 : 30,
                      onTap: _pickAttachment,
                    ),
                    // Text input
                    Expanded(
                      child: TextField(
                        controller: _ctrl,
                        focusNode: _focus,
                        minLines: 1,
                        maxLines: 8,
                        style: TextStyle(color: pt.fg, fontSize: 14),
                        cursorColor: pt.accent,
                        decoration: InputDecoration(
                          hintText: placeholder,
                          hintStyle: TextStyle(color: pt.fgDim, fontSize: 14),
                          border: InputBorder.none,
                          contentPadding: EdgeInsets.symmetric(
                            horizontal: size.width < 600 ? 4 : 8,
                            vertical: 10,
                          ),
                          isDense: true,
                        ),
                        inputFormatters: [
                          if (!(Platform.isAndroid || Platform.isIOS))
                            _SendOnEnterFormatter(onSend: _send),
                        ],
                        // Meldet der Android-Tastatur, dass dieses Feld Bilder
                        // annimmt — dadurch bietet z.B. Gboard frisch kopierte
                        // Bilder direkt in der Vorschlagsleiste an.
                        contentInsertionConfiguration: Platform.isAndroid
                            ? ContentInsertionConfiguration(
                                allowedMimeTypes: const [
                                  'image/gif',
                                  'image/png',
                                  'image/jpeg',
                                  'image/webp',
                                ],
                                onContentInserted: _handleInsertedContent,
                              )
                            : null,
                      ),
                    ),
                    // Inline tools
                    Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        _ComposerIconBtn(
                          icon: Icons.gif_box_outlined,
                          tooltip: 'GIF',
                          pt: pt,
                          size: size.width < 600 ? 22 : 26,
                          onTap: _toggleGifPicker,
                        ),
                        _ComposerIconBtn(
                          icon: Icons.tag_faces_rounded,
                          tooltip: 'Emoji',
                          pt: pt,
                          size: size.width < 600 ? 22 : 26,
                          onTap: _toggleEmojiPicker,
                        ),
                        if (size.width > 600)
                          _ComposerIconBtn(
                            icon: Icons.alternate_email_rounded,
                            tooltip: 'Mention',
                            pt: pt,
                            size: 26,
                          ),
                      ],
                    ),
                    // Send button — only on mobile
                    if (Platform.isAndroid || Platform.isIOS)
                      Padding(
                        padding: const EdgeInsets.fromLTRB(4, 4, 8, 4),
                        child: _SendButton(
                          canSend: _canSend,
                          pt: pt,
                          onTap: _send,
                        ),
                      ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _ComposerIconBtn extends StatefulWidget {
  final IconData icon;
  final String tooltip;
  final PyramidTheme pt;
  final double size;
  final VoidCallback? onTap;

  const _ComposerIconBtn({
    required this.icon,
    required this.tooltip,
    required this.pt,
    required this.size,
    this.onTap,
  });

  @override
  State<_ComposerIconBtn> createState() => _ComposerIconBtnState();
}

class _ComposerIconBtnState extends State<_ComposerIconBtn> {
  bool _hovered = false;

  @override
  Widget build(BuildContext context) {
    final platform = Theme.of(context).platform;
    final isMobile =
        platform == TargetPlatform.android || platform == TargetPlatform.iOS;
    final touchSize = isMobile ? 44.0 : widget.size;

    return MouseRegion(
      cursor: SystemMouseCursors.click,
      onEnter: (_) => setState(() => _hovered = true),
      onExit: (_) => setState(() => _hovered = false),
      child: GestureDetector(
        onTap: widget.onTap,
        child: Tooltip(
          message: widget.tooltip,
          waitDuration: const Duration(milliseconds: 500),
          child: SizedBox(
            width: touchSize,
            height: touchSize,
            child: Center(
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 150),
                width: widget.size,
                height: widget.size,
                decoration: BoxDecoration(
                  color: _hovered ? widget.pt.bgHover : Colors.transparent,
                  borderRadius: BorderRadius.circular(6),
                ),
                child: Center(
                  child: Icon(
                    widget.icon,
                    size: widget.size * 0.55,
                    color: _hovered ? widget.pt.fg : widget.pt.fgMuted,
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _SendButton extends StatefulWidget {
  final bool canSend;
  final PyramidTheme pt;
  final VoidCallback onTap;

  const _SendButton({required this.canSend, required this.pt, required this.onTap});

  @override
  State<_SendButton> createState() => _SendButtonState();
}

class _SendButtonState extends State<_SendButton> {
  bool _hovered = false;

  @override
  Widget build(BuildContext context) {
    final pt = widget.pt;
    final active = widget.canSend;

    return MouseRegion(
      cursor: active ? SystemMouseCursors.click : MouseCursor.defer,
      onEnter: (_) => setState(() => _hovered = true),
      onExit: (_) => setState(() => _hovered = false),
      child: GestureDetector(
        onTap: active ? widget.onTap : null,
        child: AnimatedContainer(
          duration: const Duration(milliseconds: 180),
          curve: Curves.easeOutBack,
          width: 36,
          height: 36,
          decoration: BoxDecoration(
            color: active ? pt.accent : pt.bg3,
            borderRadius: BorderRadius.circular(pt.rSm),
            boxShadow: active && _hovered
                ? [BoxShadow(color: pt.accentGlow, blurRadius: 12, offset: const Offset(0, 4))]
                : null,
          ),
          transform: active
              ? (_hovered
                  ? (Matrix4.diagonal3Values(1.1, 1.1, 1.0)..rotateZ(-0.26))
                  : Matrix4.diagonal3Values(1.05, 1.05, 1.0))
              : Matrix4.identity(),
          transformAlignment: Alignment.center,
          child: Center(
            child: Icon(
              Icons.send_rounded,
              size: 16,
              color: active ? pt.accentFg : pt.fgDim,
            ),
          ),
        ),
      ),
    );
  }
}

class _ReplyBar extends StatelessWidget {
  final Event event;
  final VoidCallback onClear;
  final PyramidTheme pt;

  const _ReplyBar({required this.event, required this.onClear, required this.pt});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.fromLTRB(16, 8, 8, 4),
      decoration: BoxDecoration(
        border: Border(
          top: BorderSide(color: pt.border),
          left: BorderSide(color: pt.accent, width: 3),
        ),
      ),
      child: Row(
        children: [
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  event.senderFromMemoryOrFallback.calcDisplayname(),
                  style: TextStyle(
                    color: pt.accent,
                    fontSize: 12,
                    fontWeight: FontWeight.w600,
                  ),
                ),
                Text(
                  event.body,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(color: pt.fgMuted, fontSize: 12),
                ),
              ],
            ),
          ),
          GestureDetector(
            onTap: onClear,
            child: Icon(Icons.close_rounded, size: 16, color: pt.fgDim),
          ),
        ],
      ),
    );
  }
}

class _SendOnEnterFormatter extends TextInputFormatter {
  final VoidCallback onSend;
  _SendOnEnterFormatter({required this.onSend});

  @override
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    if (newValue.text.endsWith('\n') && !oldValue.text.endsWith('\n')) {
      // Check if shift is pressed (can't detect here, just send on enter)
      // For multiline we'd need keyboard shortcuts
      WidgetsBinding.instance.addPostFrameCallback((_) => onSend());
      return oldValue;
    }
    return newValue;
  }
}
