import 'package:better_skeleton/better_skeleton.dart';
import 'package:flutter/material.dart';
import 'package:jiffy/jiffy.dart';
import 'package:kasy_kit/core/theme/theme.dart';
import 'package:kasy_kit/features/notifications/providers/models/notification.dart'
    as app;

typedef OnTapNotification = void Function(app.Notification notification);

/// A tile for the [NotificationsPage] widget.
class NotificationTile extends StatefulWidget {
  final double bgOpacity;
  final double titleOpacity;
  final Color titleColor;
  final Color descriptionColor;
  final Color dateColor;
  final Widget icon;
  final DateTime date;
  final String title;
  final String description;
  final bool showUnreadDot;
  final OnTapNotification? onTap;

  const NotificationTile({
    super.key,
    required this.bgOpacity,
    required this.titleOpacity,
    required this.icon,
    required this.date,
    required this.title,
    required this.description,
    required this.titleColor,
    required this.descriptionColor,
    required this.dateColor,
    this.showUnreadDot = false,
    this.onTap,
  });

  factory NotificationTile.active({
    required DateTime date,
    required String title,
    required String description,
    required BuildContext context,
    String? imageUrl,
    OnTapNotification? onTap,
    Key? key,
  }) =>
      NotificationTile(
        key: key,
        bgOpacity: .08,
        titleOpacity: 1,
        showUnreadDot: true,
        icon: imageUrl != null
            ? TileNotificationImage(url: imageUrl)
            : const TileNotificationIcon(active: true),
        date: date,
        title: title,
        description: description,
        titleColor: context.colors.onSurface,
        descriptionColor: context.colors.onSurface,
        dateColor: context.colors.muted,
        onTap: onTap,
      );

  factory NotificationTile.old({
    required DateTime date,
    required String title,
    required String description,
    required BuildContext context,
    String? imageUrl,
    OnTapNotification? onTap,
    Key? key,
  }) =>
      NotificationTile(
        key: key,
        bgOpacity: 0,
        titleOpacity: .6,
        icon: imageUrl != null
            ? TileNotificationImage(url: imageUrl)
            : const TileNotificationIcon(active: false),
        date: date,
        title: title,
        description: description,
        titleColor: context.colors.onSurface.withValues(alpha: 0.55),
        descriptionColor: context.colors.onSurface.withValues(alpha: 0.45),
        dateColor: context.colors.muted,
        onTap: onTap,
      );

  factory NotificationTile.from(
    BuildContext context,
    app.Notification notification, {
    Key? key,
    OnTapNotification? onTap,
  }) =>
      notification.seen
          ? NotificationTile.old(
              key: key,
              date: notification.createdAt,
              title: notification.title,
              description: notification.body,
              imageUrl: notification.imageUrl,
              context: context,
              onTap: onTap,
            )
          : NotificationTile.active(
              key: key,
              date: notification.createdAt,
              title: notification.title,
              description: notification.body,
              imageUrl: notification.imageUrl,
              context: context,
              onTap: onTap,
            );

  @override
  State<NotificationTile> createState() => _NotificationTileState();
}

class _NotificationTileState extends State<NotificationTile>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  late Animation<double> _opacityAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 500),
      vsync: this,
    );
    _opacityAnimation = Tween(
      begin: 0.0,
      end: widget.bgOpacity,
    ).animate(
      CurvedAnimation(parent: _controller, curve: Curves.decelerate),
    );
    _controller.forward();
  }

  @override
  void didUpdateWidget(covariant NotificationTile oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.bgOpacity != widget.bgOpacity) {
      _opacityAnimation = Tween(
        begin: oldWidget.bgOpacity,
        end: widget.bgOpacity,
      ).animate(
        CurvedAnimation(parent: _controller, curve: Curves.ease),
      );
      _controller.forward(from: 0);
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, child) {
        return Container(
          decoration: BoxDecoration(
            color: context.colors.primary
                .withValues(alpha: _opacityAnimation.value),
            borderRadius: KasyRadius.smBorderRadius,
          ),
          padding: const EdgeInsets.all(KasySpacing.md),
          child: child,
        );
      },
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          widget.icon,
          const SizedBox(width: KasySpacing.smd),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Flexible(
                  flex: 0,
                  child: Text(
                    widget.title,
                    style: context.textTheme.labelLarge?.copyWith(
                          color: widget.titleColor,
                        ),
                    overflow: TextOverflow.clip,
                    maxLines: 2,
                  ),
                ),
                const SizedBox(height: KasySpacing.xs),
                Flexible(
                  flex: 0,
                  child: Text(
                    widget.description,
                    style: context.textTheme.bodyMedium
                        ?.copyWith(color: widget.descriptionColor),
                    overflow: TextOverflow.ellipsis,
                    maxLines: 3,
                  ),
                ),
                const SizedBox(height: KasySpacing.smd),
                Flexible(
                  flex: 0,
                  child: Text(
                    Jiffy.parseFromDateTime(widget.date).fromNow(),
                    style: context.textTheme.bodySmall?.copyWith(
                          color: widget.dateColor,
                        ),
                  ),
                ),
              ],
            ),
          ),
          if (widget.showUnreadDot) ...[
            const SizedBox(width: KasySpacing.sm),
            Padding(
              padding: const EdgeInsets.only(top: 3),
              child: Container(
                width: 8,
                height: 8,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: context.colors.primary,
                ),
              ),
            ),
          ],
        ],
      ),
    );
  }
}

/// A thumbnail image for the [NotificationTile] widget when a notification has an image.
/// Tapping it opens a full-screen viewer.
class TileNotificationImage extends StatelessWidget {
  final String url;

  const TileNotificationImage({super.key, required this.url});

  void _openFullscreen(BuildContext context) {
    showDialog<void>(
      context: context,
      barrierColor: Colors.black87,
      builder: (dialogContext) => GestureDetector(
        onTap: () => Navigator.of(dialogContext).pop(),
        child: Scaffold(
          backgroundColor: Colors.transparent,
          body: Center(
            child: InteractiveViewer(
              child: Image.network(url, fit: BoxFit.contain),
            ),
          ),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => _openFullscreen(context),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(8),
        child: Image.network(
          url,
          width: 48,
          height: 48,
          fit: BoxFit.cover,
          errorBuilder: (context, error, stack) => const TileNotificationIcon(active: false),
          loadingBuilder: (_, child, progress) =>
              progress == null ? child : const TileNotificationIcon(active: false),
        ),
      ),
    );
  }
}

/// A small rounded-square icon badge for the [NotificationTile] widget.
/// Follows the same visual language as [SettingsIconBadge].
class TileNotificationIcon extends StatelessWidget {
  final bool active;

  const TileNotificationIcon({
    super.key,
    required this.active,
  });

  @override
  Widget build(BuildContext context) {
    final color = active
        ? context.colors.primary
        : context.colors.onSurface.withValues(alpha: 0.35);
    return Container(
      width: 40,
      height: 40,
      decoration: BoxDecoration(
        color: active
            ? context.colors.primary.withValues(alpha: 0.12)
            : context.colors.onSurface.withValues(alpha: 0.06),
        borderRadius: BorderRadius.circular(10),
      ),
      child: Icon(
        active ? KasyIcons.notificationActive : KasyIcons.notification,
        size: 20,
        color: color,
      ),
    );
  }
}

/// A skeleton for the [NotificationTile] widget.
class NotificationSkeletonTile extends StatefulWidget {
  const NotificationSkeletonTile({super.key});

  @override
  State<NotificationSkeletonTile> createState() =>
      _NotificationSkeletonTileState();
}

class _NotificationSkeletonTileState extends State<NotificationSkeletonTile>
    with SingleTickerProviderStateMixin {
  late final AnimationController animationController;

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

  @override
  void deactivate() {
    animationController.dispose();
    super.deactivate();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: KasySpacing.sm),
      child: AnimatedSkeleton(
        listenable: animationController,
        child: Container(
          height: 80,
          decoration: BoxDecoration(
            color: context.colors.primary.withValues(alpha: .1),
            borderRadius: KasyRadius.smBorderRadius,
          ),
          padding: const EdgeInsets.all(KasySpacing.md),
        ),
      ),
    );
  }
}
