import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:komet/core/config/app_frost.dart';
import 'package:komet/core/config/app_stories.dart';
import 'package:komet/core/utils/haptics.dart';
import 'package:komet/frontend/screens/stories/story_owner_info.dart';
import 'package:komet/frontend/screens/stories/story_ring.dart';
import 'package:komet/frontend/screens/stories/story_viewer_screen.dart';
import 'package:komet/frontend/widgets/encryption_lock_badge.dart';
import 'package:komet/frontend/widgets/glossy_pill.dart';
import 'package:komet/frontend/widgets/online_dot.dart';
import 'package:komet/frontend/widgets/profile_hero.dart';
import 'package:komet/main.dart' show storiesModule;
import 'package:komet/models/story.dart';

class ChatHeaderRow extends StatelessWidget {
  final bool glossy;
  final bool frosted;
  final bool liquid;
  final BackdropKey? backdropKey;
  final ColorScheme cs;
  final bool embedded;
  final int chatId;
  final Object heroTag;
  final String name;
  final String imageUrl;
  final String chatType;
  final bool isOfficial;
  final bool encrypted;
  final int myId;
  final ValueListenable<String> headerStatus;
  final ValueListenable<int> scheduledCount;
  final ValueListenable<int> otherUnread;
  final bool showCall;
  final VoidCallback? onClose;
  final VoidCallback onOpenInfo;
  final VoidCallback onOpenScheduled;
  final VoidCallback onCall;
  final void Function(BuildContext) onMenu;

  const ChatHeaderRow({
    super.key,
    required this.glossy,
    required this.frosted,
    this.liquid = false,
    this.backdropKey,
    required this.cs,
    required this.embedded,
    required this.chatId,
    required this.heroTag,
    required this.name,
    required this.imageUrl,
    required this.chatType,
    required this.isOfficial,
    this.encrypted = false,
    required this.myId,
    required this.headerStatus,
    required this.scheduledCount,
    required this.otherUnread,
    required this.showCall,
    required this.onClose,
    required this.onOpenInfo,
    required this.onOpenScheduled,
    required this.onCall,
    required this.onMenu,
  });

  @override
  Widget build(BuildContext context) =>
      glossy ? _glossyRow(context) : _materialRow(context);

  Color? get _pillColor => frosted || liquid ? AppFrost.pillTint(cs) : null;

  double? get _pillBlur => frosted && !liquid ? AppFrost.sigma : null;

  Widget _glossyRow(BuildContext context) {
    final nameStyle = TextStyle(
      color: cs.onSurface,
      fontSize: 17,
      fontWeight: FontWeight.w600,
      fontFamily: 'Outfit',
    );
    return Padding(
      padding: const EdgeInsets.fromLTRB(10, 4, 10, 8),
      child: Row(
        children: [
          _backWithBadge(
            cs,
            SizedBox(
              width: 56,
              height: 56,
              child: GlossyPill(
                color: _pillColor,
                blurSigma: _pillBlur,
                liquid: liquid,
                backdropKey: backdropKey,
                onTap: () {
                  if (embedded) {
                    onClose?.call();
                  } else {
                    Navigator.pop(context);
                  }
                },
                child: Center(
                  child: Icon(
                    embedded ? Symbols.close : Symbols.arrow_back,
                    color: cs.onSurface,
                    weight: 500,
                    size: 24,
                  ),
                ),
              ),
            ),
          ),
          const SizedBox(width: 8),
          Expanded(
            child: GlossyPill(
              color: _pillColor,
              blurSigma: _pillBlur,
              liquid: liquid,
              backdropKey: backdropKey,
              onTap: onOpenInfo,
              padding: const EdgeInsets.fromLTRB(6, 6, 16, 6),
              child: Row(
                children: [
                  _withOnlineDot(
                    cs,
                    _heroAvatar(
                      44,
                      (d) => imageUrl.isNotEmpty
                          ? CircleAvatar(
                              radius: d / 2,
                              backgroundImage: CachedNetworkImageProvider(
                                imageUrl,
                                maxWidth: 144,
                                maxHeight: 144,
                              ),
                            )
                          : CircleAvatar(
                              radius: d / 2,
                              backgroundColor: cs.primaryContainer,
                              child: Text(
                                name.isNotEmpty ? name[0].toUpperCase() : '?',
                                style: TextStyle(
                                  color: cs.onPrimaryContainer,
                                  fontSize: d * 0.36,
                                  fontWeight: FontWeight.w600,
                                  fontFamily: 'Outfit',
                                ),
                              ),
                            ),
                    ),
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Row(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Flexible(
                              child: ProfileHeroName(
                                tag: heroTag,
                                text: name,
                                style: nameStyle,
                                child: Text(
                                  name,
                                  style: nameStyle,
                                  maxLines: 1,
                                  overflow: TextOverflow.ellipsis,
                                ),
                              ),
                            ),
                            if (isOfficial) ...[
                              const SizedBox(width: 4),
                              Icon(
                                Symbols.verified,
                                color: cs.primary,
                                size: 16,
                                weight: 600,
                                fill: 1,
                              ),
                            ],
                          ],
                        ),
                        ValueListenableBuilder<String>(
                          valueListenable: headerStatus,
                          builder: (context, status, _) => Text(
                            status,
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(
                              color: cs.onSurfaceVariant,
                              fontSize: 13,
                              fontWeight: FontWeight.w400,
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
          const SizedBox(width: 8),
          GlossyPill(
            color: _pillColor,
            blurSigma: _pillBlur,
            liquid: liquid,
            backdropKey: backdropKey,
            padding: const EdgeInsets.symmetric(horizontal: 2),
            child: SizedBox(
              height: 56,
              child: Row(
                mainAxisSize: MainAxisSize.min,
                children: [
                  ValueListenableBuilder<int>(
                    valueListenable: scheduledCount,
                    builder: (_, count, _) => count > 0
                        ? IconButton(
                            icon: Icon(
                              Symbols.schedule,
                              weight: 500,
                              color: cs.onSurface,
                            ),
                            onPressed: onOpenScheduled,
                          )
                        : const SizedBox.shrink(),
                  ),
                  if (showCall)
                    IconButton(
                      icon: Icon(
                        Symbols.call,
                        weight: 500,
                        color: cs.onSurface,
                      ),
                      onPressed: onCall,
                    ),
                  Builder(
                    builder: (btnContext) => IconButton(
                      icon: Icon(
                        Symbols.more_vert,
                        weight: 500,
                        color: cs.onSurface,
                      ),
                      onPressed: () => onMenu(btnContext),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _materialRow(BuildContext context) {
    final nameStyle = TextStyle(
      color: cs.onSurface,
      fontSize: 16,
      fontWeight: FontWeight.w600,
      fontFamily: 'Outfit',
    );
    return Row(
      children: [
        _backWithBadge(
          cs,
          IconButton(
            icon: Icon(
              embedded ? Symbols.close : Symbols.arrow_back,
              weight: 400,
              color: cs.onSurface,
            ),
            onPressed: () {
              if (embedded) {
                onClose?.call();
              } else {
                Navigator.pop(context);
              }
            },
          ),
        ),
        Expanded(
          child: InkWell(
            onTap: onOpenInfo,
            child: Row(
              children: [
                _withOnlineDot(
                  cs,
                  _heroAvatar(
                    36,
                    (d) => imageUrl.isNotEmpty
                        ? CircleAvatar(
                            radius: d / 2,
                            backgroundImage: CachedNetworkImageProvider(
                              imageUrl,
                              maxWidth: 144,
                              maxHeight: 144,
                            ),
                          )
                        : CircleAvatar(
                            radius: d / 2,
                            backgroundColor: cs.primaryContainer,
                            child: Text(
                              name.isNotEmpty ? name[0].toUpperCase() : '?',
                              style: TextStyle(
                                color: cs.onPrimaryContainer,
                                fontSize: d / 3,
                              ),
                            ),
                          ),
                  ),
                  dotSize: 11,
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Flexible(
                            child: ProfileHeroName(
                              tag: heroTag,
                              text: name,
                              style: nameStyle,
                              child: Text(
                                name,
                                style: nameStyle,
                                maxLines: 1,
                                overflow: TextOverflow.ellipsis,
                              ),
                            ),
                          ),
                          if (isOfficial) ...[
                            const SizedBox(width: 4),
                            Icon(
                              Symbols.verified,
                              color: cs.primary,
                              size: 16,
                              weight: 600,
                              fill: 1,
                            ),
                          ],
                        ],
                      ),
                      ValueListenableBuilder<String>(
                        valueListenable: headerStatus,
                        builder: (context, status, _) => Text(
                          status,
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                          style: TextStyle(
                            color: cs.onSurfaceVariant,
                            fontSize: 12,
                            fontWeight: FontWeight.w400,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
        ValueListenableBuilder<int>(
          valueListenable: scheduledCount,
          builder: (_, count, _) => count > 0
              ? IconButton(
                  icon: Icon(
                    Symbols.schedule,
                    weight: 400,
                    color: cs.onSurface,
                  ),
                  onPressed: onOpenScheduled,
                )
              : const SizedBox.shrink(),
        ),
        if (showCall)
          IconButton(
            icon: Icon(Symbols.call, weight: 400, color: cs.onSurface),
            onPressed: onCall,
          ),
        Builder(
          builder: (btnContext) => IconButton(
            icon: Icon(Symbols.more_vert, weight: 400, color: cs.onSurface),
            onPressed: () => onMenu(btnContext),
          ),
        ),
      ],
    );
  }

  int get _storyOwnerId => chatType == 'DIALOG' ? chatId ^ myId : chatId;

  Widget _heroAvatar(
    double size,
    Widget Function(double diameter) avatarBuilder,
  ) {
    final ownerId = _storyOwnerId;
    if (!AppStories.current.value || ownerId <= 0) {
      return ProfileHeroAvatar(
        tag: heroTag,
        size: size,
        child: avatarBuilder(size),
      );
    }
    const gap = 3.0;
    return ValueListenableBuilder<int>(
      valueListenable: storiesModule.storiesChanged,
      builder: (context, _, _) {
        final preview = storiesModule.previewFor(ownerId);
        final hasStory = preview != null && !preview.isEmpty;
        final inner = hasStory ? size - gap * 2 : size;
        return GestureDetector(
          behavior: hasStory
              ? HitTestBehavior.opaque
              : HitTestBehavior.deferToChild,
          onTap: hasStory ? () => _openStories(context, preview) : null,
          child: StoryAvatarRing(
            diameter: inner,
            total: preview?.totalCount ?? 0,
            read: preview?.readCount ?? 0,
            strokeWidth: 2,
            ringGap: hasStory ? gap : 0,
            haloWidth: 1.2,
            child: ProfileHeroAvatar(
              tag: heroTag,
              size: inner,
              child: avatarBuilder(inner),
            ),
          ),
        );
      },
    );
  }

  void _openStories(BuildContext context, StoryPreview preview) {
    Haptics.tap();
    unawaited(
      openStoryViewer(
        context,
        previews: [preview],
        origin: storyOriginOf(context),
        ownerOverrides: {
          preview.owner.ownerId: StoryOwnerInfo(
            name: name,
            avatarUrl: imageUrl.isEmpty ? null : imageUrl,
          ),
        },
      ),
    );
  }

  Widget _withOnlineDot(ColorScheme cs, Widget avatar, {double dotSize = 12}) {
    final otherId = chatId ^ myId;
    final showDot = chatType == 'DIALOG' && myId != 0 && otherId > 0;
    return Stack(
      clipBehavior: Clip.none,
      children: [
        avatar,
        if (showDot)
          Positioned(
            right: 0,
            bottom: 0,
            child: OnlineDot(
              userId: otherId,
              borderColor: cs.surface,
              size: dotSize,
            ),
          ),
        if (encrypted)
          Positioned(
            left: -2,
            bottom: -2,
            child: EncryptionLockBadge(size: dotSize + 4),
          ),
      ],
    );
  }

  Widget _backWithBadge(ColorScheme cs, Widget button) {
    return Stack(
      clipBehavior: Clip.none,
      alignment: Alignment.center,
      children: [
        button,
        Positioned(
          right: -2,
          bottom: 0,
          child: IgnorePointer(child: _backUnreadBadge(cs)),
        ),
      ],
    );
  }

  Widget _backUnreadBadge(ColorScheme cs) {
    return ValueListenableBuilder<int>(
      valueListenable: otherUnread,
      builder: (context, count, _) {
        return AnimatedScale(
          scale: count > 0 ? 1.0 : 0.0,
          duration: const Duration(milliseconds: 200),
          curve: Curves.easeOutBack,
          child: Container(
            constraints: const BoxConstraints(minWidth: 18),
            height: 18,
            padding: const EdgeInsets.symmetric(horizontal: 5),
            decoration: BoxDecoration(
              color: cs.primary,
              borderRadius: BorderRadius.circular(9),
              border: Border.all(color: cs.surface, width: 1.5),
            ),
            alignment: Alignment.center,
            child: _RollingCount(
              count: count > 99 ? 99 : count,
              style: TextStyle(
                color: cs.onPrimary,
                fontSize: 10.5,
                fontWeight: FontWeight.w700,
                height: 1.0,
              ),
            ),
          ),
        );
      },
    );
  }
}

class _RollingCount extends StatefulWidget {
  final int count;
  final TextStyle style;

  const _RollingCount({required this.count, required this.style});

  @override
  State<_RollingCount> createState() => _RollingCountState();
}

class _RollingCountState extends State<_RollingCount> {
  late int _count = widget.count;
  bool _increasing = true;

  @override
  void didUpdateWidget(_RollingCount old) {
    super.didUpdateWidget(old);
    if (widget.count != _count) {
      _increasing = widget.count > _count;
      _count = widget.count;
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedSwitcher(
      duration: const Duration(milliseconds: 260),
      switchInCurve: Curves.easeOut,
      switchOutCurve: Curves.easeIn,
      transitionBuilder: (child, anim) {
        final incoming = (child.key as ValueKey<int>).value == _count;
        final Offset begin;
        if (incoming) {
          begin = _increasing ? const Offset(0, -1) : const Offset(0, 1);
        } else {
          begin = _increasing ? const Offset(0, 1) : const Offset(0, -1);
        }
        return ClipRect(
          child: FadeTransition(
            opacity: anim,
            child: SlideTransition(
              position: Tween(begin: begin, end: Offset.zero).animate(anim),
              child: child,
            ),
          ),
        );
      },
      child: Text(
        '${widget.count}',
        key: ValueKey<int>(widget.count),
        style: widget.style,
      ),
    );
  }
}
