import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shadcn_ui/shadcn_ui.dart';

import '../../core/app_colors.dart';
import '../../core/app_design_tokens.dart';
import '../../core/app_module_visuals.dart';
import '../../core/navigation_provider.dart';
import '../../providers/data_providers.dart';
import '../../services/in_app_notification_service.dart';
import '../../widgets/app_empty_state.dart';
import '../../widgets/common_widgets.dart';

Future<bool> acknowledgeBeforeNotificationOpen({
  required Future<void> Function() acknowledge,
  VoidCallback? onAcknowledged,
  required VoidCallback open,
}) async {
  var acknowledged = true;
  try {
    await acknowledge();
    onAcknowledged?.call();
  } catch (_) {
    acknowledged = false;
  }
  open();
  return acknowledged;
}

class NotificationCenterPage extends ConsumerStatefulWidget {
  const NotificationCenterPage({super.key});

  @override
  ConsumerState<NotificationCenterPage> createState() =>
      _NotificationCenterPageState();
}

class _NotificationCenterPageState
    extends ConsumerState<NotificationCenterPage> {
  InAppNotificationHistory? _history;
  bool _loading = true;
  bool _markingAll = false;
  bool _showEarlier = false;
  String? _error;

  InAppNotificationService get _service =>
      ref.read(inAppNotificationServiceProvider);

  @override
  void initState() {
    super.initState();
    Future.microtask(_load);
  }

  Future<void> _load() async {
    if (mounted) {
      setState(() {
        _loading = true;
        _error = null;
      });
    }
    try {
      final history = await _service.getHistory();
      if (!mounted) return;
      setState(() {
        _history = history;
        _loading = false;
      });
      ref.invalidate(notificationUnreadCountProvider);
    } catch (error) {
      if (!mounted) return;
      setState(() {
        _error = '$error';
        _loading = false;
      });
    }
  }

  Future<void> _open(InAppNotification item) async {
    if (!item.isRead) {
      await acknowledgeBeforeNotificationOpen(
        acknowledge: () => _service.acknowledge(item.id),
        onAcknowledged: () {
          if (!mounted) return;
          setState(() {
            final current = _history;
            if (current == null) return;
            _history = InAppNotificationHistory(
              unreadCount: (current.unreadCount - 1).clamp(
                0,
                current.unreadCount,
              ),
              items: current.items
                  .map(
                    (value) => value.id == item.id
                        ? value.copyWith(isRead: true)
                        : value,
                  )
                  .toList(),
            );
          });
          ref.invalidate(notificationUnreadCountProvider);
        },
        open: () {
          if (mounted) _openTarget(item);
        },
      );
      return;
    }

    _openTarget(item);
  }

  void _openTarget(InAppNotification item) {
    if (!mounted || item.actionType == null) return;
    switch (item.actionType) {
      case 'medication':
        pushRoute(ref, 'medCheckIn', params: {'id': item.actionTargetId ?? ''});
        return;
      case 'exercise':
        pushRoute(ref, 'exercisePlan');
        return;
      case 'health':
        pushRoute(ref, 'trend', params: {'type': item.actionTargetId ?? ''});
        return;
      case 'report':
        final reportId = item.actionTargetId;
        if (reportId != null && reportId.isNotEmpty) {
          pushRoute(ref, 'aiAnalysis', params: {'id': reportId});
        }
        return;
    }
  }

  Future<void> _markAllRead() async {
    if (_markingAll || (_history?.unreadCount ?? 0) == 0) return;
    setState(() => _markingAll = true);
    try {
      await _service.markAllRead();
      if (!mounted) return;
      final current = _history;
      if (current != null) {
        setState(
          () => _history = InAppNotificationHistory(
            unreadCount: 0,
            items: current.items
                .map((item) => item.copyWith(isRead: true))
                .toList(),
          ),
        );
      }
      ref.invalidate(notificationUnreadCountProvider);
    } finally {
      if (mounted) setState(() => _markingAll = false);
    }
  }

  Future<void> _delete(InAppNotification item) async {
    try {
      await _service.delete(item.id);
      if (!mounted) return;
      final current = _history;
      if (current != null) {
        setState(
          () => _history = InAppNotificationHistory(
            unreadCount: item.isRead
                ? current.unreadCount
                : (current.unreadCount - 1).clamp(0, current.unreadCount),
            items: current.items.where((value) => value.id != item.id).toList(),
          ),
        );
      }
      ref.invalidate(notificationUnreadCountProvider);
    } catch (_) {
      if (mounted) await _load();
    }
  }

  @override
  Widget build(BuildContext context) {
    final items = _history?.items ?? const <InAppNotification>[];
    final unread = _history?.unreadCount ?? 0;

    return Scaffold(
      backgroundColor: AppColors.background,
      appBar: AppBar(
        backgroundColor: Colors.white,
        elevation: 0,
        scrolledUnderElevation: 0,
        surfaceTintColor: Colors.transparent,
        leading: IconButton(
          icon: const Icon(Icons.arrow_back, color: AppColors.textPrimary),
          onPressed: () => popRoute(ref),
        ),
        title: const Text(
          '通知中心',
          style: TextStyle(
            fontSize: 19,
            fontWeight: FontWeight.w600,
            color: AppColors.textPrimary,
          ),
        ),
        centerTitle: true,
        actions: [
          if (unread > 0)
            TextButton(
              onPressed: _markingAll ? null : _markAllRead,
              child: _markingAll
                  ? const SizedBox(
                      width: 16,
                      height: 16,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Text(
                      '全部已读',
                      style: TextStyle(
                        fontSize: 15,
                        fontWeight: FontWeight.w700,
                      ),
                    ),
            ),
          IconButton(
            tooltip: '通知设置',
            icon: const Icon(Icons.settings_outlined),
            onPressed: () => pushRoute(ref, 'notificationPrefs'),
          ),
          const SizedBox(width: 4),
        ],
      ),
      body: ColoredBox(
        color: AppColors.background,
        child: SizedBox.expand(
          child: RefreshIndicator(
            onRefresh: _load,
            color: AppColors.primary,
            child: _buildBody(items, unread),
          ),
        ),
      ),
    );
  }

  Widget _buildBody(List<InAppNotification> items, int unread) {
    if (_loading) return const Center(child: CircularProgressIndicator());
    if (_error != null) {
      return _MessageState(
        icon: LucideIcons.wifiOff,
        title: '通知加载失败',
        message: '请检查网络连接后重试',
        buttonText: '重新加载',
        onPressed: _load,
      );
    }
    if (items.isEmpty) {
      return const _MessageState(
        icon: LucideIcons.bellOff,
        title: '暂时没有通知',
        message: '用药、运动、健康指标和报告消息会显示在这里',
      );
    }

    final today = <InAppNotification>[];
    final earlier = <InAppNotification>[];
    final now = DateTime.now();
    for (final item in items) {
      final local = item.createdAt.toLocal();
      final isToday =
          local.year == now.year &&
          local.month == now.month &&
          local.day == now.day;
      (isToday ? today : earlier).add(item);
    }

    return ListView(
      physics: const AlwaysScrollableScrollPhysics(),
      padding: const EdgeInsets.fromLTRB(16, 14, 16, 32),
      children: [
        if (unread > 0) _UnreadHint(unreadCount: unread),
        if (today.isNotEmpty) ...[
          const _SectionTitle('今天'),
          const SizedBox(height: 10),
          _NotificationGroup(
            children: [
              for (var i = 0; i < today.length; i++)
                _buildDismissible(today[i], showDivider: i < today.length - 1),
            ],
          ),
        ],
        if (earlier.isNotEmpty) ...[
          if (today.isNotEmpty) const SizedBox(height: 18),
          _CollapsibleSectionTitle(
            text: '更早',
            count: earlier.length,
            expanded: _showEarlier,
            onTap: () => setState(() => _showEarlier = !_showEarlier),
          ),
          const SizedBox(height: 10),
          if (_showEarlier)
            _NotificationGroup(
              children: [
                for (var i = 0; i < earlier.length; i++)
                  _buildDismissible(
                    earlier[i],
                    showDivider: i < earlier.length - 1,
                  ),
              ],
            ),
        ],
      ],
    );
  }

  Widget _buildDismissible(
    InAppNotification item, {
    required bool showDivider,
  }) => Dismissible(
    key: ValueKey(item.id),
    direction: DismissDirection.endToStart,
    background: Container(
      alignment: Alignment.centerRight,
      padding: const EdgeInsets.only(right: 26),
      color: AppColors.error,
      child: const Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(LucideIcons.trash2, color: Colors.white, size: 22),
          SizedBox(width: 8),
          Text(
            '删除',
            style: TextStyle(
              color: Colors.white,
              fontSize: 15,
              fontWeight: FontWeight.w700,
            ),
          ),
        ],
      ),
    ),
    onDismissed: (_) => _delete(item),
    child: _NotificationRow(
      item: item,
      showDivider: showDivider,
      onTap: () => _open(item),
    ),
  );
}

class _NotificationGroup extends StatelessWidget {
  final List<Widget> children;

  const _NotificationGroup({required this.children});

  @override
  Widget build(BuildContext context) {
    return Container(
      clipBehavior: Clip.antiAlias,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: AppRadius.xlBorder,
      ),
      child: Column(children: children),
    );
  }
}

class _UnreadHint extends StatelessWidget {
  final int unreadCount;

  const _UnreadHint({required this.unreadCount});

  @override
  Widget build(BuildContext context) => Container(
    margin: const EdgeInsets.fromLTRB(0, 2, 0, 10),
    padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9),
    decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: AppRadius.mdBorder,
    ),
    child: Row(
      children: [
        const Icon(
          LucideIcons.bellRing,
          size: 17,
          color: AppColors.textSecondary,
        ),
        const SizedBox(width: 8),
        RichText(
          text: TextSpan(
            style: const TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w600,
              color: AppColors.textSecondary,
            ),
            children: [
              const TextSpan(text: '还有 '),
              TextSpan(
                text: '$unreadCount',
                style: const TextStyle(
                  fontWeight: FontWeight.w600,
                  color: AppColors.errorText,
                ),
              ),
              const TextSpan(text: ' 条未读消息'),
            ],
          ),
        ),
      ],
    ),
  );
}

class _SectionTitle extends StatelessWidget {
  final String text;

  const _SectionTitle(this.text);

  @override
  Widget build(BuildContext context) => _SectionShell(
    child: Text(
      text,
      style: const TextStyle(
        fontSize: 13,
        fontWeight: FontWeight.w700,
        color: AppColors.textHint,
        letterSpacing: 0,
      ),
    ),
  );
}

class _SectionShell extends StatelessWidget {
  final Widget child;

  const _SectionShell({required this.child});

  @override
  Widget build(BuildContext context) =>
      Padding(padding: const EdgeInsets.fromLTRB(2, 12, 2, 8), child: child);
}

class _CollapsibleSectionTitle extends StatelessWidget {
  final String text;
  final int count;
  final bool expanded;
  final VoidCallback onTap;

  const _CollapsibleSectionTitle({
    required this.text,
    required this.count,
    required this.expanded,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) => GestureDetector(
    behavior: HitTestBehavior.opaque,
    onTap: onTap,
    child: _SectionShell(
      child: Row(
        children: [
          Text(
            '$text · $count',
            style: const TextStyle(
              fontSize: 13,
              fontWeight: FontWeight.w700,
              color: AppColors.textHint,
              letterSpacing: 0,
            ),
          ),
          const Spacer(),
          Text(
            expanded ? '收起' : '展开',
            style: const TextStyle(
              fontSize: 12,
              fontWeight: FontWeight.w700,
              color: AppColors.textHint,
            ),
          ),
          const SizedBox(width: 4),
          Icon(
            expanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down,
            size: 18,
            color: AppColors.textHint,
          ),
        ],
      ),
    ),
  );
}

class _NotificationRow extends StatelessWidget {
  final InAppNotification item;
  final bool showDivider;
  final VoidCallback onTap;

  const _NotificationRow({
    required this.item,
    required this.showDivider,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    final visual = _NotificationVisual.of(item);
    return Material(
      color: Colors.white,
      child: InkWell(
        onTap: onTap,
        child: Container(
          color: Colors.white,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ConstrainedBox(
                constraints: BoxConstraints(minHeight: showDivider ? 81 : 82),
                child: Padding(
                  padding: const EdgeInsets.fromLTRB(14, 10, 10, 10),
                  child: Row(
                    children: [
                      Container(
                        width: 40,
                        height: 40,
                        decoration: BoxDecoration(
                          color: visual.lightIconSurface
                              ? AppColors.device
                              : null,
                          gradient: visual.lightIconSurface
                              ? null
                              : visual.gradient,
                          borderRadius: AppRadius.smBorder,
                        ),
                        child: Icon(
                          visual.icon,
                          size: 21,
                          color: visual.iconColor,
                        ),
                      ),
                      const SizedBox(width: 11),
                      Expanded(
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            Row(
                              children: [
                                Expanded(
                                  child: Text(
                                    item.title,
                                    maxLines: 1,
                                    overflow: TextOverflow.ellipsis,
                                    style: TextStyle(
                                      fontSize: 15,
                                      fontWeight: item.isRead
                                          ? FontWeight.w600
                                          : FontWeight.w700,
                                      color: AppColors.textPrimary,
                                      height: 1.2,
                                    ),
                                  ),
                                ),
                                const SizedBox(width: 6),
                                Container(
                                  padding: const EdgeInsets.symmetric(
                                    horizontal: 6,
                                    vertical: 2,
                                  ),
                                  decoration: BoxDecoration(
                                    color: visual.lightColor,
                                    borderRadius: AppRadius.pillBorder,
                                  ),
                                  child: Text(
                                    visual.label,
                                    style: TextStyle(
                                      fontSize: 11,
                                      fontWeight: FontWeight.w600,
                                      color: visual.color,
                                    ),
                                  ),
                                ),
                              ],
                            ),
                            const SizedBox(height: 4),
                            Text(
                              item.message,
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style: const TextStyle(
                                fontSize: 13,
                                height: 1.2,
                                fontWeight: FontWeight.w500,
                                color: AppColors.textSecondary,
                              ),
                            ),
                          ],
                        ),
                      ),
                      const SizedBox(width: 8),
                      SizedBox(
                        width: 68,
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          crossAxisAlignment: CrossAxisAlignment.end,
                          children: [
                            if (item.isRead)
                              const SizedBox(height: 8)
                            else
                              Container(
                                width: 8,
                                height: 8,
                                decoration: const BoxDecoration(
                                  color: AppColors.error,
                                  shape: BoxShape.circle,
                                ),
                              ),
                            const SizedBox(height: 7),
                            Text(
                              _formatTime(item.createdAt),
                              maxLines: 1,
                              textAlign: TextAlign.right,
                              style: const TextStyle(
                                fontSize: 11,
                                fontWeight: FontWeight.w600,
                                color: AppColors.textHint,
                              ),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              ),
              if (showDivider)
                const Padding(
                  padding: EdgeInsets.only(left: 65),
                  child: Divider(
                    height: 1,
                    thickness: 0.7,
                    color: Color(0xFFE8ECF2),
                  ),
                ),
            ],
          ),
        ),
      ),
    );
  }

  static String _formatTime(DateTime value) {
    final local = value.toLocal();
    final now = DateTime.now();
    final time =
        '${local.hour.toString().padLeft(2, '0')}:'
        '${local.minute.toString().padLeft(2, '0')}';
    if (local.year == now.year &&
        local.month == now.month &&
        local.day == now.day) {
      return time;
    }
    if (local.year == now.year) return '${local.month}-${local.day} $time';
    return '${local.year}-${local.month}-${local.day} $time';
  }
}

class _NotificationVisual {
  final IconData icon;
  final Color color;
  final Color lightColor;
  final Gradient gradient;
  final Color iconColor;
  final bool lightIconSurface;
  final String label;

  const _NotificationVisual(
    this.icon,
    this.color,
    this.lightColor,
    this.gradient,
    this.iconColor,
    this.lightIconSurface,
    this.label,
  );

  factory _NotificationVisual.fromModule(
    AppModuleVisual visual, {
    Color iconColor = Colors.white,
    bool lightIconSurface = false,
  }) {
    return _NotificationVisual(
      visual.icon,
      visual.color,
      visual.lightColor,
      visual.gradient,
      iconColor,
      lightIconSurface,
      visual.label,
    );
  }

  factory _NotificationVisual.of(InAppNotification item) {
    final kind = (item.actionType ?? item.type).toLowerCase();
    switch (kind) {
      case 'exercise':
      case 'exercisereminder':
        return _NotificationVisual.fromModule(AppModuleVisuals.exercise);
      case 'health':
      case 'health_record_reminder':
        return _NotificationVisual.fromModule(AppModuleVisuals.health);
      case 'report':
        return _NotificationVisual.fromModule(AppModuleVisuals.report);
      case 'medication':
      case 'medicationreminder':
        return _NotificationVisual.fromModule(AppModuleVisuals.medication);
      case 'diet':
        return _NotificationVisual.fromModule(AppModuleVisuals.diet);
      case 'followup':
      case 'follow_up_reminder':
        return _NotificationVisual.fromModule(AppModuleVisuals.followup);
      case 'doctor':
      case 'consultation':
        return _NotificationVisual.fromModule(AppModuleVisuals.doctor);
      case 'device':
      case 'bluetooth':
        return _NotificationVisual.fromModule(
          AppModuleVisuals.device,
          iconColor: Colors.white,
          lightIconSurface: true,
        );
      default:
        return _NotificationVisual.fromModule(AppModuleVisuals.notification);
    }
  }
}

class _MessageState extends StatelessWidget {
  final IconData icon;
  final String title;
  final String message;
  final String? buttonText;
  final VoidCallback? onPressed;

  const _MessageState({
    required this.icon,
    required this.title,
    required this.message,
    this.buttonText,
    this.onPressed,
  });

  @override
  Widget build(BuildContext context) => ListView(
    physics: const AlwaysScrollableScrollPhysics(),
    padding: const EdgeInsets.fromLTRB(28, 100, 28, 32),
    children: [
      AppEmptyState(
        icon: icon,
        iconColor: onPressed == null ? AppColors.notification : AppColors.error,
        title: title,
        subtitle: message,
        padding: const EdgeInsets.all(24),
        action: buttonText == null
            ? null
            : SizedBox(
                width: 140,
                child: AppGradientOutlineButton(
                  label: buttonText!,
                  onPressed: onPressed,
                ),
              ),
      ),
    ],
  );
}
