import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import '../../../core/app_colors.dart';
import '../../../core/app_theme.dart';
import '../../../core/navigation_provider.dart';
import '../../../providers/chat_provider.dart';
import '../../../providers/data_providers.dart';

/// 卡片入场动画包装（从下往上滑入 + 淡入）
class _AnimatedCardEntry extends StatefulWidget {
  final Widget child;
  const _AnimatedCardEntry({required this.child});

  @override
  State<_AnimatedCardEntry> createState() => _AnimatedCardEntryState();
}

class _AnimatedCardEntryState extends State<_AnimatedCardEntry>
    with SingleTickerProviderStateMixin {
  late final _ctrl = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 600),
  );
  late final _slide = Tween<Offset>(
    begin: const Offset(0, 0.12),
    end: Offset.zero,
  ).animate(CurvedAnimation(parent: _ctrl, curve: Curves.easeOutCubic));
  late final _fade = Tween<double>(
    begin: 0.0,
    end: 1.0,
  ).animate(CurvedAnimation(parent: _ctrl, curve: Curves.easeOut));

  @override
  void initState() {
    super.initState();
    _ctrl.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _fade,
      child: SlideTransition(position: _slide, child: widget.child),
    );
  }
}

/// 对话消息列表
class ChatMessagesView extends ConsumerWidget {
  final ScrollController scrollCtrl;
  final List<ChatMessage> messages;

  const ChatMessagesView({
    super.key,
    required this.scrollCtrl,
    required this.messages,
  });

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final chatState = ref.watch(chatProvider);

    if (messages.isEmpty) {
      return Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              width: 80,
              height: 80,
              decoration: BoxDecoration(
                color: AppTheme.primaryLight,
                borderRadius: BorderRadius.circular(40),
              ),
              child: const Icon(
                Icons.health_and_safety,
                size: 40,
                color: AppTheme.primary,
              ),
            ),
            const SizedBox(height: 16),
            Text(
              '开始和小脉健康对话吧',
              style: Theme.of(context).textTheme.bodyMedium,
            ),
            const SizedBox(height: 8),
            const Text(
              '记录健康数据，获取专业建议',
              style: TextStyle(fontSize: 17, color: AppColors.textHint),
            ),
          ],
        ),
      );
    }

    return ListView.builder(
      controller: scrollCtrl,
      reverse: false,
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      itemCount: messages.length,
      itemBuilder: (context, index) {
        final msg = messages[index];
        return _buildMessageContent(context, ref, msg, chatState);
      },
    );
  }

  // ─── 消息分发 ─────────────────────────────────────────────

  Widget _buildMessageContent(
    BuildContext context,
    WidgetRef ref,
    ChatMessage msg,
    ChatState chatState,
  ) {
    switch (msg.type) {
      case MessageType.agentWelcome:
        final storedAgent = _parseAgentFromName(
          msg.metadata?['agent'] as String?,
        );
        return _buildAgentWelcomeCard(context, ref, msg, storedAgent);
      case MessageType.taskCard:
        return _buildTaskCardInChat(context, ref);
      case MessageType.dataConfirm:
        return _buildDataConfirmCard(context, ref, msg);
      default:
        if (!msg.isUser &&
            chatState.isStreaming &&
            msg.content.trim().isEmpty) {
          return _buildThinkingBubble(context, chatState.thinkingText);
        }
        return _buildTextBubble(context, msg, chatState);
    }
  }

  // ═══════════════════════════════════════════════════════════
  // 1. AgentWelcomeCard — 智能体欢迎卡片（蚂蚁阿福风格 + 美化版）
  // ═══════════════════════════════════════════════════════════

  Widget _buildAgentWelcomeCard(
    BuildContext context,
    WidgetRef ref,
    ChatMessage msg,
    ActiveAgent agent,
  ) {
    final info = _agentInfo(agent);
    final actions = agent.actions;
    final screenWidth = MediaQuery.of(context).size.width;
    final agentColors = _agentColors(agent);
    final artworkPath = _agentArtworkPath(agent);

    return _AnimatedCardEntry(
      child: Align(
        alignment: Alignment.centerLeft,
        child: Container(
          margin: const EdgeInsets.only(bottom: 16),
          constraints: BoxConstraints(maxWidth: screenWidth * 0.95),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(24),
            boxShadow: [
              BoxShadow(
                color: const Color(0xFF6B5CE7).withValues(alpha: 0.12),
                blurRadius: 28,
                offset: const Offset(0, 14),
              ),
              BoxShadow(
                color: const Color(0xFF101828).withValues(alpha: 0.06),
                blurRadius: 12,
                offset: const Offset(0, 4),
              ),
            ],
          ),
          clipBehavior: Clip.antiAlias,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              // ── 标题区域 ──
              Stack(
                children: [
                  Positioned.fill(
                    child: DecoratedBox(
                      decoration: BoxDecoration(
                        gradient: LinearGradient(
                          colors: [
                            Colors.white,
                            agentColors.bg.withValues(alpha: 0.86),
                            agentColors.accent.withValues(alpha: 0.12),
                          ],
                          stops: const [0.0, 0.58, 1.0],
                          begin: Alignment.topLeft,
                          end: Alignment.bottomRight,
                        ),
                      ),
                    ),
                  ),
                  Positioned(
                    right: 18,
                    top: 18,
                    child: _MiniSignalStrip(colors: agentColors),
                  ),
                  Positioned(
                    right: 18,
                    bottom: 18,
                    child: _LinearAccentMark(colors: agentColors),
                  ),
                  Container(
                    width: double.infinity,
                    padding: const EdgeInsets.fromLTRB(18, 20, 18, 22),
                    child: Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        _AgentMark(icon: info.$1, colors: agentColors),
                        const SizedBox(width: 16),
                        Expanded(
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Container(
                                padding: const EdgeInsets.symmetric(
                                  horizontal: 10,
                                  vertical: 4,
                                ),
                                decoration: BoxDecoration(
                                  color: Colors.white.withValues(alpha: 0.76),
                                  borderRadius: BorderRadius.circular(999),
                                  border: Border.all(
                                    color: agentColors.accent.withValues(
                                      alpha: 0.18,
                                    ),
                                  ),
                                ),
                                child: Row(
                                  mainAxisSize: MainAxisSize.min,
                                  children: [
                                    Icon(
                                      Icons.graphic_eq,
                                      size: 14,
                                      color: agentColors.accent,
                                    ),
                                    const SizedBox(width: 4),
                                    Text(
                                      'AI 智能助手',
                                      style: TextStyle(
                                        fontSize: 13,
                                        fontWeight: FontWeight.w600,
                                        color: agentColors.accent,
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                              const SizedBox(height: 9),
                              Text(
                                info.$2,
                                style: const TextStyle(
                                  fontSize: 24,
                                  fontWeight: FontWeight.w800,
                                  color: AppColors.textPrimary,
                                ),
                              ),
                              const SizedBox(height: 8),
                              Text(
                                info.$3,
                                style: const TextStyle(
                                  fontSize: 16,
                                  color: AppColors.textSecondary,
                                  height: 1.4,
                                ),
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),

              // ── 插画展示 ──
              Image.asset(
                artworkPath,
                width: double.infinity,
                height: 206,
                fit: BoxFit.cover,
              ),

              // ── AI问诊引导 ──
              if (agent == ActiveAgent.consultation) ...[
                const SizedBox(height: 14),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  child: Container(
                    width: double.infinity,
                    padding: const EdgeInsets.all(16),
                    decoration: BoxDecoration(
                      color: const Color(0xFFF0F4FF),
                      borderRadius: BorderRadius.circular(14),
                    ),
                    child: const Text(
                      '在下方输入框描述您的症状，AI医生将为您提供专业建议',
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        fontSize: 14,
                        color: AppColors.textSecondary,
                      ),
                    ),
                  ),
                ),
              ],

              if (actions.isNotEmpty) ...[
                const SizedBox(height: 14),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      for (int i = 0; i < actions.length; i++) ...[
                        if (i > 0) const SizedBox(width: 10),
                        Flexible(
                          child: _buildActionButton(
                            actions[i],
                            context,
                            ref,
                            agentColors,
                          ),
                        ),
                      ],
                    ],
                  ),
                ),
              ],

              // ── 底部提示 ──
              const SizedBox(height: 16),
              Padding(
                padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
                child: Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 14,
                    vertical: 10,
                  ),
                  decoration: BoxDecoration(
                    color: agentColors.bg,
                    borderRadius: BorderRadius.circular(14),
                    border: Border.all(
                      color: agentColors.accent.withValues(alpha: 0.14),
                    ),
                  ),
                  child: Row(
                    children: [
                      Icon(
                        Icons.lightbulb_outline,
                        size: 18,
                        color: agentColors.accent,
                      ),
                      const SizedBox(width: 8),
                      Expanded(
                        child: Text(
                          _agentTip(agent),
                          style: TextStyle(
                            fontSize: 15,
                            color: AppColors.textPrimary.withAlpha(180),
                            fontWeight: FontWeight.w500,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildActionButton(
    _AgentAction a,
    BuildContext context,
    WidgetRef ref,
    _AgentColors colors,
  ) {
    return InkWell(
      onTap: () {
        if (a.label == '服药打卡') {
          pushRoute(ref, 'medCheckIn');
        } else if (a.action == 'pickFoodCamera' ||
            a.action == 'pickFoodGallery') {
          ref.read(dietActionProvider.notifier).trigger(a.action!);
        } else if (a.route != null) {
          if (a.route == 'camera' || a.route == 'gallery') {
            ref.read(cameraActionProvider.notifier).trigger(a.route!);
          } else {
            pushRoute(ref, a.route!);
          }
        }
      },
      borderRadius: BorderRadius.circular(28),
      child: Container(
        padding: const EdgeInsets.all(1.4),
        decoration: BoxDecoration(
          gradient: AppColors.actionOutlineGradient,
          borderRadius: BorderRadius.circular(28),
        ),
        child: Container(
          padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 18),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(26.5),
          ),
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              ShaderMask(
                shaderCallback: (bounds) =>
                    AppColors.actionOutlineGradient.createShader(bounds),
                child: Icon(a.icon, size: 24, color: Colors.white),
              ),
              const SizedBox(width: 10),
              Text(
                a.label,
                style: const TextStyle(
                  fontSize: 17,
                  fontWeight: FontWeight.w700,
                  color: AppColors.textPrimary,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  String _agentArtworkPath(ActiveAgent agent) {
    return switch (agent) {
      ActiveAgent.consultation => 'assets/branding/agent_consultation_card.png',
      ActiveAgent.health => 'assets/branding/agent_health_card.png',
      ActiveAgent.diet => 'assets/branding/agent_diet_card.png',
      ActiveAgent.medication => 'assets/branding/agent_medication_card.png',
      ActiveAgent.report => 'assets/branding/agent_report_card.png',
      ActiveAgent.exercise => 'assets/branding/agent_exercise_card.png',
      _ => 'assets/branding/agent_health_card.png',
    };
  }

  // ═══════════════════════════════════════════════════════════
  // 2. DataConfirmCard — 统一确认卡片（紫白蓝风格）
  // ═══════════════════════════════════════════════════════════

  Widget _buildDataConfirmCard(
    BuildContext context,
    WidgetRef ref,
    ChatMessage msg,
  ) {
    final meta = msg.metadata ?? <String, dynamic>{};
    final backendType = meta['type'] as String? ?? '';
    final screenWidth = MediaQuery.of(context).size.width;

    // 识别是哪种数据类型
    final isMedication =
        backendType == 'medication' ||
        (meta['name'] != null &&
            meta['name'].toString().isNotEmpty &&
            backendType != 'exercise');
    final isExercise = backendType == 'exercise';
    final isHealth = !isMedication && !isExercise;

    // 根据类型获取显示字段
    String title = '数据确认';
    IconData titleIcon = Icons.assignment;
    String mainLabel = '';
    String mainValue = '';
    String mainUnit = '';
    bool abnormal = meta['abnormal'] as bool? ?? false;
    String recordTime = meta['recordTime'] as String? ?? '';

    List<_ConfirmField> fields = [];

    if (isMedication) {
      // 药品录入 — 主展示区已显示药名+剂量，详情只列额外信息
      title = '药品录入确认';
      titleIcon = Icons.medication_liquid_outlined;
      mainLabel = meta['name'] as String? ?? '';
      mainValue = meta['dosage'] as String? ?? '';
      mainUnit = '';

      if (recordTime.isEmpty) recordTime = _formatTime(msg.createdAt);
      final time = meta['time'] as String? ?? '';
      if (time.isNotEmpty) {
        final timeValue = meta['服药时间'] as String? ?? time;
        fields.add(
          _ConfirmField(label: '服药时间', value: timeValue),
        );
      }
      final frequency = meta['frequency'] as String? ?? '';
      if (frequency.isNotEmpty) {
        final freqValue = meta['频率'] as String? ?? _freqLabel(frequency);
        fields.add(
          _ConfirmField(label: '频率', value: freqValue),
        );
      }
      final duration = meta['duration_days'] as int?;
      if (duration != null && duration > 0) {
        final durationValue = meta['服用天数'] as String? ?? '$duration 天';
        fields.add(
          _ConfirmField(label: '服用天数', value: durationValue),
        );
      }
    } else if (isExercise) {
      // 运动计划 — 主展示区大号显示运动名，字段列时长/频率/天数
      title = '运动计划确认';
      titleIcon = Icons.directions_run_outlined;
      final exName =
          (meta['value'] ??
                  meta['name'] ??
                  meta['exerciseType'] ??
                  meta['运动类型'] ??
                  '')
              .toString();
      final exUnitRaw =
          (meta['unit'] ?? meta['duration_unit'] ?? meta['durationUnit'] ?? '')
              .toString();
      final exDaysRaw = meta['durationDays'] ?? meta['day_count'];
      final exDays = int.tryParse(exDaysRaw?.toString() ?? '') ?? 0;

      // 解析 "每天30分钟" → 频率=每天, 时长=30分钟
      final freqMatch = RegExp(r'^(每天|每周|每月)').firstMatch(exUnitRaw);
      final durMatch = RegExp(r'(\d+分钟)').firstMatch(exUnitRaw);
      final freq = freqMatch?.group(1) ?? '';
      final dur = durMatch?.group(1) ?? exUnitRaw;

      mainLabel = '运动计划';
      mainValue = exName.isNotEmpty ? exName : '运动计划';
      mainUnit = '';

      if (recordTime.isEmpty) recordTime = _formatTime(msg.createdAt);
      if (dur.isNotEmpty) {
        fields.add(_ConfirmField(label: '运动时长', value: dur));
      }
      if (freq.isNotEmpty) {
        fields.add(_ConfirmField(label: '频率', value: freq));
      }
      if (exDays > 0) {
        fields.add(_ConfirmField(label: '计划天数', value: '$exDays天'));
      }
      final intensity = (meta['intensity'] ?? meta['运动强度'] ?? '').toString();
      if (intensity.isNotEmpty) {
        fields.add(
          _ConfirmField(label: '运动强度', value: intensity),
        );
      }
      final calories =
          (meta['calories'] ?? meta['calorie'] ?? meta['消耗热量'] ?? '')
              .toString();
      if (calories.isNotEmpty) {
        fields.add(
          _ConfirmField(label: '消耗热量', value: '$calories kcal'),
        );
      }
    } else {
      // 健康指标 — 主展示区已显示指标+数值+单位，详情只列额外信息
      title = '健康数据确认';
      titleIcon = Icons.monitor_heart_outlined;
      mainLabel = _getMetricName(backendType);
      mainValue = meta['value'] as String? ?? '';
      mainUnit = meta['unit'] as String? ?? _getMetricUnit(backendType);

      if (recordTime.isEmpty) recordTime = _formatTime(msg.createdAt);
      final timeValue = meta['记录时间'] as String? ?? recordTime;
      fields.add(
        _ConfirmField(label: '记录时间', value: timeValue),
      );
      final note = meta['note'] as String? ?? '';
      if (note.isNotEmpty) {
        final noteValue = meta['备注'] as String? ?? note;
        fields.add(
          _ConfirmField(label: '备注', value: noteValue),
        );
      }
    }

    return _AnimatedCardEntry(
      child: Align(
        alignment: Alignment.centerLeft,
        child: Container(
          margin: const EdgeInsets.only(bottom: 16),
          constraints: BoxConstraints(maxWidth: screenWidth * 0.95),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(28),
            boxShadow: [
              BoxShadow(
                color: const Color(0xFF6366F1).withValues(alpha: 0.10),
                blurRadius: 28,
                offset: const Offset(0, 14),
              ),
              BoxShadow(
                color: const Color(0xFF101828).withValues(alpha: 0.06),
                blurRadius: 12,
                offset: const Offset(0, 4),
              ),
            ],
          ),
          clipBehavior: Clip.antiAlias,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              // ── 标题区域 ──
              Container(
                width: double.infinity,
                padding: const EdgeInsets.fromLTRB(20, 20, 20, 18),
                decoration: const BoxDecoration(
                  gradient: LinearGradient(
                    begin: Alignment.topLeft,
                    end: Alignment.bottomRight,
                    colors: [Color(0xFFFFFFFF), Color(0xFFF7F4FF)],
                  ),
                ),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Container(
                      width: 56,
                      height: 56,
                      decoration: BoxDecoration(
                        gradient: AppColors.actionOutlineGradient,
                        borderRadius: BorderRadius.circular(16),
                        boxShadow: [
                          BoxShadow(
                            color: AppColors.auraIndigo.withValues(alpha: 0.18),
                            blurRadius: 10,
                            offset: const Offset(0, 4),
                          ),
                        ],
                      ),
                      child: Icon(titleIcon, size: 28, color: Colors.white),
                    ),
                    const SizedBox(width: 14),
                    Expanded(
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            title,
                            style: const TextStyle(
                              fontSize: 22,
                              fontWeight: FontWeight.w700,
                              color: AppColors.textPrimary,
                            ),
                          ),
                          const SizedBox(height: 6),
                          Row(
                            children: [
                              Icon(
                                Icons.access_time,
                                size: 15,
                                color: AppColors.iconColor,
                              ),
                              const SizedBox(width: 4),
                              Text(
                                recordTime,
                                style: const TextStyle(
                                  fontSize: 15,
                                  color: AppColors.textSecondary,
                                ),
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),

              // ── 主要数据展示区（大卡片） ──
              Padding(
                padding: const EdgeInsets.fromLTRB(20, 14, 20, 0),
                child: Container(
                  padding: const EdgeInsets.all(1.4),
                  decoration: BoxDecoration(
                    gradient: AppColors.actionOutlineGradient,
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: Container(
                    width: double.infinity,
                    padding: const EdgeInsets.all(20),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(18),
                    ),
                    child: Row(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Container(
                          width: 68,
                          height: 68,
                          decoration: BoxDecoration(
                            gradient: AppColors.lightGradient,
                            borderRadius: BorderRadius.circular(18),
                          ),
                          child: Center(
                            child: isHealth
                                ? Icon(
                                    _getMetricIconData(backendType),
                                    size: 34,
                                    color: AppColors.primaryDark,
                                  )
                                : Icon(
                                    isMedication
                                        ? Icons.medication_liquid_outlined
                                        : Icons.directions_run_outlined,
                                    size: 36,
                                    color: AppColors.iconColor,
                                  ),
                          ),
                        ),
                        const SizedBox(width: 16),
                        Expanded(
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                mainLabel,
                                style: const TextStyle(
                                  fontSize: 17,
                                  color: AppColors.textSecondary,
                                ),
                              ),
                              if (mainValue.isNotEmpty) ...[
                                const SizedBox(height: 8),
                                RichText(
                                  text: TextSpan(
                                    children: [
                                      TextSpan(
                                        text: mainValue,
                                        style: TextStyle(
                                          fontSize: 36,
                                          fontWeight: FontWeight.w800,
                                          color: abnormal
                                              ? AppColors.error
                                              : AppColors.textPrimary,
                                          letterSpacing: -0.5,
                                        ),
                                      ),
                                      if (mainUnit.isNotEmpty)
                                        TextSpan(
                                          text: ' $mainUnit',
                                          style: TextStyle(
                                            fontSize: 19,
                                            color: abnormal
                                                ? AppColors.error
                                                : AppColors.iconColor,
                                            fontWeight: FontWeight.w500,
                                          ),
                                        ),
                                    ],
                                  ),
                                ),
                              ],
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),

              // ── 异常提示 ──
              if (abnormal) ...[
                const SizedBox(height: 12),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  child: Container(
                    width: double.infinity,
                    padding: const EdgeInsets.symmetric(
                      horizontal: 16,
                      vertical: 12,
                    ),
                    decoration: BoxDecoration(
                      color: AppColors.error.withAlpha(10),
                      borderRadius: BorderRadius.circular(14),
                      border: Border.all(color: AppColors.error.withAlpha(30)),
                    ),
                    child: Row(
                      children: [
                        Container(
                          width: 32,
                          height: 32,
                          decoration: BoxDecoration(
                            color: AppColors.error.withAlpha(15),
                            borderRadius: BorderRadius.circular(10),
                          ),
                          child: Icon(
                            Icons.warning_amber_rounded,
                            size: 20,
                            color: AppColors.error,
                          ),
                        ),
                        const SizedBox(width: 10),
                        Expanded(
                          child: Text(
                            '数值偏高，建议关注并咨询医生',
                            style: TextStyle(
                              fontSize: 16,
                              color: AppColors.error,
                              fontWeight: FontWeight.w500,
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],

              // ── 详细字段列表（可点击修改） ──
              if (fields.isNotEmpty) ...[
                const SizedBox(height: 12),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  child: Container(
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(20),
                      border: Border.all(color: AppColors.border),
                    ),
                    child: Column(
                      children: [
                        for (int i = 0; i < fields.length; i++) ...[
                          if (i > 0)
                            Container(
                              height: 1,
                              color: AppColors.borderLight,
                              margin: const EdgeInsets.symmetric(
                                horizontal: 16,
                              ),
                            ),
                          _buildFieldRow(fields[i]),
                        ],
                      ],
                    ),
                  ),
                ),
              ],

              // ── 确认按钮（白色底+渐变边框） ──
              const SizedBox(height: 18),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 20),
                child: Container(
                  width: double.infinity,
                  height: 56,
                  padding: const EdgeInsets.all(1.4),
                  decoration: BoxDecoration(
                    gradient: AppColors.actionOutlineGradient,
                    borderRadius: BorderRadius.circular(20),
                    boxShadow: [
                      BoxShadow(
                        color: AppColors.auraIndigo.withValues(alpha: 0.18),
                        blurRadius: 18,
                        offset: const Offset(0, 8),
                      ),
                    ],
                  ),
                  child: msg.confirmed
                      ? Container(
                          decoration: BoxDecoration(
                            gradient: AppColors.successButtonGradient,
                            borderRadius: BorderRadius.circular(18),
                          ),
                          child: const Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Icon(
                                Icons.check_circle_outline,
                                size: 22,
                                color: Colors.white,
                              ),
                              SizedBox(width: 8),
                              Text(
                                '录入成功',
                                style: TextStyle(
                                  fontSize: 19,
                                  fontWeight: FontWeight.w700,
                                  color: Colors.white,
                                ),
                              ),
                            ],
                          ),
                        )
                      : Material(
                          color: Colors.transparent,
                          child: InkWell(
                            onTap: () async {
                              final error = await ref
                                  .read(chatProvider.notifier)
                                  .confirmMessage(msg.id);
                              if (error != null && context.mounted) {
                                ScaffoldMessenger.of(context).showSnackBar(
                                  SnackBar(content: Text(error)),
                                );
                              }
                            },
                            borderRadius: BorderRadius.circular(18),
                            child: Container(
                              decoration: BoxDecoration(
                                color: Colors.white,
                                borderRadius: BorderRadius.circular(18),
                              ),
                              child: Row(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: [
                                  Container(
                                    width: 32,
                                    height: 32,
                                    decoration: BoxDecoration(
                                      gradient: AppColors.actionOutlineGradient,
                                      borderRadius: BorderRadius.circular(10),
                                    ),
                                    child: const Icon(
                                      Icons.check_rounded,
                                      size: 19,
                                      color: Colors.white,
                                    ),
                                  ),
                                  const SizedBox(width: 10),
                                  const Text(
                                    '确认录入',
                                    style: TextStyle(
                                      fontSize: 18,
                                      fontWeight: FontWeight.w800,
                                      color: AppColors.textPrimary,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ),
                        ),
                ),
              ),
              const SizedBox(height: 20),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildFieldRow(_ConfirmField field) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          SizedBox(
            width: 80,
            child: Text(
              field.label,
              style: const TextStyle(fontSize: 15, color: AppColors.textHint),
            ),
          ),
          const SizedBox(width: 12),
          Expanded(
            child: Text(
              field.value.isNotEmpty ? field.value : '未设置',
              style: const TextStyle(
                fontSize: 17,
                fontWeight: FontWeight.w600,
                color: AppColors.textPrimary,
              ),
            ),
          ),
        ],
      ),
    );
  }

  // ═══════════════════════════════════════════════════════════
  // 3. ThinkingBubble — 思考动画
  // ═══════════════════════════════════════════════════════════
  Widget _buildThinkingBubble(BuildContext context, String? thinkingText) {
    return Align(
      alignment: Alignment.centerLeft,
      child: Container(
        margin: const EdgeInsets.only(bottom: 12),
        padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14),
        decoration: BoxDecoration(
          color: AppColors.cardBackground,
          borderRadius: const BorderRadius.only(
            topLeft: Radius.circular(4),
            topRight: Radius.circular(20),
            bottomLeft: Radius.circular(20),
            bottomRight: Radius.circular(20),
          ),
          border: Border.all(color: AppColors.border, width: 1.5),
          boxShadow: [
            BoxShadow(
              color: AppTheme.primary.withAlpha(12),
              blurRadius: 10,
              offset: const Offset(0, 3),
            ),
          ],
        ),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Container(
              width: 26,
              height: 26,
              padding: const EdgeInsets.all(5),
              decoration: BoxDecoration(
                color: AppTheme.primaryLight,
                borderRadius: BorderRadius.circular(13),
              ),
              child: const CircularProgressIndicator(
                strokeWidth: 2.2,
                color: AppTheme.primary,
              ),
            ),
            const SizedBox(width: 10),
            Text(
              thinkingText?.isNotEmpty == true ? thinkingText! : '正在分析...',
              style: const TextStyle(fontSize: 17, color: AppColors.textHint),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildTextBubble(
    BuildContext context,
    ChatMessage msg,
    ChatState? chatState,
  ) {
    final isUser = msg.isUser;
    final imageUrl = msg.metadata?['imageUrl'] as String?;
    final localPath = msg.metadata?['localImagePath'] as String?;
    final hasImage = imageUrl != null || localPath != null;

    return Align(
      alignment: isUser ? Alignment.centerRight : Alignment.centerLeft,
      child: Container(
        margin: const EdgeInsets.only(bottom: 12),
        constraints: BoxConstraints(
          maxWidth: MediaQuery.of(context).size.width * 0.82,
        ),
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
        decoration: BoxDecoration(
          color: isUser ? Colors.white : AppColors.cardBackground,
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(isUser ? 20 : 4),
            topRight: Radius.circular(isUser ? 4 : 20),
            bottomLeft: const Radius.circular(20),
            bottomRight: const Radius.circular(20),
          ),
          border: Border.all(
            color: isUser ? const Color(0xFFE8E4FF) : AppColors.border,
            width: isUser ? 1 : 1.5,
          ),
          boxShadow: isUser
              ? []
              : [
                  BoxShadow(
                    color: AppTheme.primary.withAlpha(12),
                    blurRadius: 10,
                    offset: const Offset(0, 3),
                  ),
                ],
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 文字内容
            if (isUser)
              SelectableText(
                msg.content,
                style: const TextStyle(
                  fontSize: 19,
                  color: AppColors.textPrimary,
                  height: 1.5,
                ),
              )
            else
              MarkdownBody(
                data: _cleanAiText(msg.content),
                selectable: true,
                styleSheet: MarkdownStyleSheet(
                  p: const TextStyle(
                    fontSize: 19,
                    color: AppColors.textPrimary,
                    height: 1.5,
                  ),
                  strong: const TextStyle(
                    fontSize: 19,
                    color: AppColors.textPrimary,
                    height: 1.5,
                    fontWeight: FontWeight.w700,
                  ),
                  h1: const TextStyle(
                    fontSize: 21,
                    color: AppColors.textPrimary,
                    fontWeight: FontWeight.w700,
                  ),
                  h2: const TextStyle(
                    fontSize: 20,
                    color: AppColors.textPrimary,
                    fontWeight: FontWeight.w700,
                  ),
                ),
              ),

            // 图片缩略图（在文字下方）
            if (hasImage)
              Padding(
                padding: const EdgeInsets.only(top: 8),
                child: GestureDetector(
                  onTap: () => _showFullImage(context, localPath ?? imageUrl),
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(8),
                    child: ConstrainedBox(
                      constraints: const BoxConstraints(
                        maxWidth: 160,
                        maxHeight: 120,
                      ),
                      child: localPath != null
                          ? Image.file(File(localPath), fit: BoxFit.cover)
                          : imageUrl != null
                          ? Image.network(
                              imageUrl,
                              fit: BoxFit.cover,
                              errorBuilder: (_, e, s) => Container(
                                width: 80,
                                height: 60,
                                decoration: BoxDecoration(
                                  color: AppColors.backgroundSecondary,
                                  borderRadius: BorderRadius.circular(8),
                                ),
                                child: const Icon(
                                  Icons.image,
                                  size: 28,
                                  color: AppColors.textHint,
                                ),
                              ),
                            )
                          : const SizedBox.shrink(),
                    ),
                  ),
                ),
              ),

            if (!isUser && msg.content.isNotEmpty)
              Padding(
                padding: const EdgeInsets.only(top: 10),
                child: Row(
                  children: [
                    const CircleAvatar(
                      radius: 10,
                      backgroundColor: AppTheme.primaryLight,
                      child: Icon(
                        Icons.chat_bubble_outline,
                        size: 17,
                        color: AppTheme.primary,
                      ),
                    ),
                    const SizedBox(width: 6),
                    const Text(
                      '小脉健康',
                      style: TextStyle(fontSize: 15, color: AppColors.textHint),
                    ),
                    const SizedBox(width: 4),
                    const Text(
                      '仅供参考',
                      style: TextStyle(fontSize: 14, color: AppColors.textHint),
                    ),
                  ],
                ),
              ),
          ],
        ),
      ),
    );
  }

  // ═══════════════════════════════════════════════════════════
  // 工具方法
  // ═══════════════════════════════════════════════════════════

  static void _showFullImage(BuildContext context, String? path) {
    if (path == null) return;
    showDialog(
      context: context,
      builder: (ctx) => Dialog(
        backgroundColor: Colors.black,
        insetPadding: const EdgeInsets.all(24),
        child: Stack(
          alignment: Alignment.center,
          children: [
            ClipRRect(
              borderRadius: BorderRadius.circular(12),
              child: InteractiveViewer(
                child: path.startsWith('http')
                    ? Image.network(path, fit: BoxFit.contain)
                    : Image.file(File(path), fit: BoxFit.contain),
              ),
            ),
            Positioned(
              top: 8,
              right: 8,
              child: GestureDetector(
                onTap: () => Navigator.pop(ctx),
                child: Container(
                  padding: const EdgeInsets.all(6),
                  decoration: BoxDecoration(
                    color: Colors.white54,
                    shape: BoxShape.circle,
                  ),
                  child: const Icon(Icons.close, size: 21),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  /// 清理 AI 返回文本中的异常占位符（Markdown 格式交给 MarkdownBody 渲染）
  static String _cleanAiText(String text) {
    var t = text;
    // 移除 $1、$2 等占位符
    t = t.replaceAll(RegExp(r'\$\d+'), '');
    // 移除残留 HTML 标签
    t = t.replaceAll(RegExp(r'<[^>]+>'), '');
    // 行首 # 超过 3 个降为 ###
    t = t.replaceAllMapped(RegExp(r'^#{4,}\s', multiLine: true), (_) => '### ');
    // 压缩多余空行
    t = t.replaceAll(RegExp(r'\n{3,}'), '\n\n');
    return t.trim();
  }

  String _freqLabel(String freq) {
    switch (freq.toLowerCase()) {
      case 'daily':
        return '每天';
      case 'everyotherday':
        return '隔天';
      case 'weekly':
        return '每周';
      default:
        return freq;
    }
  }

  String _formatTime(DateTime dt) {
    final now = DateTime.now();
    final today = DateTime(now.year, now.month, now.day);
    final thatDay = DateTime(dt.year, dt.month, dt.day);
    if (thatDay == today) {
      return '今天 ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}';
    }
    if (thatDay == today.subtract(const Duration(days: 1))) {
      return '昨天 ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}';
    }
    return '${dt.month}/${dt.day} ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}';
  }

  String _getMetricUnit(String type) {
    switch (type.toLowerCase()) {
      case 'blood_pressure':
        return 'mmHg';
      case 'heart_rate':
        return 'bpm';
      case 'glucose':
        return 'mmol/L';
      case 'spo2':
        return '%';
      case 'weight':
        return 'kg';
      case 'exercise':
        return '分钟/天';
      default:
        return '';
    }
  }

  IconData _getMetricIconData(String type) {
    switch (type.toLowerCase()) {
      case 'blood_pressure':
        return Icons.bloodtype_outlined;
      case 'heart_rate':
        return Icons.monitor_heart_outlined;
      case 'glucose':
        return Icons.water_drop_outlined;
      case 'spo2':
        return Icons.air_outlined;
      case 'weight':
        return Icons.monitor_weight_outlined;
      case 'exercise':
        return Icons.directions_run_outlined;
      default:
        return Icons.query_stats_outlined;
    }
  }

  String _getMetricName(String type) {
    switch (type.toLowerCase()) {
      case 'blood_pressure':
        return '血压';
      case 'heart_rate':
        return '心率';
      case 'glucose':
        return '血糖';
      case 'spo2':
        return '血氧';
      case 'weight':
        return '体重';
      case 'exercise':
        return '运动计划';
      default:
        return '健康指标';
    }
  }

  static _AgentColors _agentColors(ActiveAgent agent) {
    return switch (agent) {
      ActiveAgent.consultation => _AgentColors(
        gradient: [Color(0xFFFFCAD4), Color(0xFFFF9AAE)],
        bg: const Color(0xFFFFF4F6),
        border: const Color(0xFFFFDFE7),
        iconBg: const Color(0xFFFFEEF2),
        accent: const Color(0xFFFF7F98),
        verticalGradient: true,
      ),
      ActiveAgent.health => _AgentColors(
        gradient: [Color(0xFFA1FFCE), Color(0xFF69DB8F)],
        bg: const Color(0xFFF4FEF2),
        border: const Color(0xFFD4F0C8),
        iconBg: const Color(0xFFF0FCEF),
        accent: const Color(0xFF52B87A),
        verticalGradient: true,
      ),
      ActiveAgent.diet => _AgentColors(
        gradient: [Color(0xFFF6D365), Color(0xFFFDA085)],
        bg: const Color(0xFFFFF7F0),
        border: const Color(0xFFFFE8D4),
        iconBg: const Color(0xFFFFF0E4),
        accent: const Color(0xFFF89C5B),
        verticalGradient: true,
      ),
      ActiveAgent.medication => _AgentColors(
        gradient: [Color(0xFF89F7FE), Color(0xFF66A6FF)],
        bg: const Color(0xFFF4F6FF),
        border: const Color(0xFFDDE6FF),
        iconBg: const Color(0xFFEFF3FF),
        accent: const Color(0xFF4F8FF7),
        verticalGradient: true,
      ),
      ActiveAgent.report => _AgentColors(
        gradient: [Color(0xFFE0C3FC), Color(0xFF8EC5FC)],
        bg: const Color(0xFFF8F5FF),
        border: const Color(0xFFE9E0FF),
        iconBg: const Color(0xFFF2EDFF),
        accent: const Color(0xFF9D8AF8),
        verticalGradient: true,
      ),
      ActiveAgent.exercise => _AgentColors(
        gradient: [Color(0xFFB6F2FF), Color(0xFF7DD3FC)],
        bg: const Color(0xFFF0FCFF),
        border: const Color(0xFFD8F5FC),
        iconBg: const Color(0xFFEAFBFF),
        accent: const Color(0xFF38BDE8),
        verticalGradient: true,
      ),
      _ => _AgentColors(
        gradient: [AppColors.primary, AppColors.blueMeasure],
        bg: const Color(0xFFF6F3FF),
        border: const Color(0xFFE7E0FF),
        iconBg: const Color(0xFFF0EDFF),
        accent: AppColors.primary,
      ),
    };
  }

  static (_AgentIcon, String, String) _agentInfo(ActiveAgent agent) {
    return switch (agent) {
      ActiveAgent.health => (LucideIcons.heartPulse, '记数据', '录入血压、血糖、心率等日常指标'),
      ActiveAgent.diet => (LucideIcons.utensils, '拍饮食', '拍照识别食物热量和营养成分'),
      ActiveAgent.medication => (LucideIcons.pill, '药管家', '管理药品、提醒服药、追踪用量'),
      ActiveAgent.consultation => (
        LucideIcons.messageCircle,
        'AI问诊',
        'AI智能问诊，描述症状获取建议',
      ),
      ActiveAgent.report => (LucideIcons.fileText, '报告分析', '上传体检报告，AI 辅助解读'),
      ActiveAgent.exercise => (LucideIcons.activity, '运动', '制定运动计划，打卡记录进度'),
      _ => (Icons.forum_outlined, 'AI 助手', '血管病患者的 AI 健康管理助手'),
    };
  }

  static String _agentTip(ActiveAgent agent) => switch (agent) {
    ActiveAgent.health => '直接说出您的症状或数据，如"血压130/85，心率72"',
    ActiveAgent.diet => '拍照或描述您吃了什么，如"早餐吃了两个鸡蛋一杯牛奶"',
    ActiveAgent.medication => '说出药品名称和用法，如"每天早晚各一片阿司匹林"',
    ActiveAgent.consultation => '描述您的症状和不适感，如"最近总是头晕胸闷"',
    ActiveAgent.report => '上传您的检查报告，AI 将自动提取指标并解读',
    ActiveAgent.exercise => '说出运动计划，如"每天散步30分钟坚持一周"',
    _ => '直接描述您的需求，AI 会自动为您记录和分析',
  };

  static ActiveAgent _parseAgentFromName(String? name) {
    switch (name) {
      case 'consultation':
        return ActiveAgent.consultation;
      case 'health':
        return ActiveAgent.health;
      case 'diet':
        return ActiveAgent.diet;
      case 'medication':
        return ActiveAgent.medication;
      case 'report':
        return ActiveAgent.report;
      case 'exercise':
        return ActiveAgent.exercise;
      default:
        return ActiveAgent.default_;
    }
  }

  Widget _buildTaskCardInChat(BuildContext context, WidgetRef ref) {
    final health = ref.watch(latestHealthProvider);
    final reminders = ref.watch(medicationReminderProvider);
    return health.when(
      data: (data) => _taskCardBubble(context, ref, data, reminders),
      loading: () =>
          _taskCardBubble(context, ref, {}, const AsyncValue.loading()),
      error: (_, e) =>
          _taskCardBubble(context, ref, {}, const AsyncValue.loading()),
    );
  }

  Widget _taskCardBubble(
    BuildContext context,
    WidgetRef ref,
    Map<String, dynamic> healthData,
    AsyncValue<List<Map<String, dynamic>>> reminders,
  ) {
    final now = DateTime.now();
    final tasks = <Widget>[];

    // ── 解析健康指标 ──
    final bp = healthData['BloodPressure'];
    final bpText = bp is Map
        ? '${bp['systolic'] ?? '--'}/${bp['diastolic'] ?? '--'}'
        : null;
    final hr = healthData['HeartRate'];
    final hrText = hr is Map && hr['value'] is num ? '${hr['value']}' : null;
    final bs = healthData['Glucose'];
    final bsText = bs is Map && bs['value'] is num ? '${bs['value']}' : null;
    final bo = healthData['SpO2'];
    final boText = bo is Map && bo['value'] is num ? '${bo['value']}' : null;
    final wt = healthData['Weight'];
    final wtText = wt is Map && wt['value'] is num ? '${wt['value']}' : null;
    final allNull =
        bpText == null &&
        hrText == null &&
        bsText == null &&
        boText == null &&
        wtText == null;

    // 异常检测
    final bpAbnormal =
        bp is Map && bp['systolic'] is int && (bp['systolic'] as int) >= 140;
    final hasAbnormal = bpAbnormal;

    // ── 1. 健康指标 ──
    const healthIconColor = Color(0xFF3B82F6);
    const healthIconBg = Color(0xFFDBEAFE);
    if (allNull) {
      tasks.add(
        _taskRow(
          context,
          Icons.monitor_heart_outlined,
          '健康指标',
          trailing: '今日暂无记录，点击录入',
          status: 'pending',
          iconColor: healthIconColor,
          iconBg: healthIconBg,
          onTap: () => pushRoute(ref, 'trend'),
        ),
      );
    } else if (hasAbnormal) {
      // 有异常时显示异常指标
      final abnormalParts = <String>[];
      if (bpAbnormal) {
        abnormalParts.add('血压 ${bp['systolic']}/${bp['diastolic']} 偏高');
      }
      tasks.add(
        _taskRow(
          context,
          Icons.warning_amber_rounded,
          '健康指标',
          trailing: abnormalParts.join(' · '),
          status: 'warning',
          iconColor: healthIconColor,
          iconBg: healthIconBg,
          onTap: () => pushRoute(ref, 'trend'),
        ),
      );
    } else {
      // 全部正常
      tasks.add(
        _taskRow(
          context,
          Icons.check_circle,
          '健康指标',
          trailing: '指标正常',
          status: 'done',
          iconColor: healthIconColor,
          iconBg: healthIconBg,
          onTap: () => pushRoute(ref, 'trend'),
        ),
      );
    }

    // ── 2. 运动 ──
    const exIconColor = Color(0xFFF59E0B);
    const exIconBg = Color(0xFFFEF3C7);
    final exercisePlan = ref.watch(currentExercisePlanProvider);
    var hasExercise = false;
    exercisePlan.when(
      data: (plan) {
        if (plan != null) {
          final items =
              (plan['items'] as List?)?.cast<Map<String, dynamic>>() ?? [];
          final today = '${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}';
          final todayItem = items.cast<Map<String, dynamic>?>().firstWhere(
            (i) => i?['scheduledDate']?.toString() == today,
            orElse: () => null,
          );
          if (todayItem != null && todayItem['isRestDay'] != true) {
            hasExercise = true;
            final done = todayItem['isCompleted'] == true;
            final name = items.isNotEmpty
                ? (items.first['exerciseType']?.toString() ?? '运动')
                : '运动';
            final dur = items.isNotEmpty
                ? (items.first['durationMinutes']?.toString() ?? '30')
                : '30';
            tasks.add(
              _taskRow(
                context,
                Icons.directions_run,
                '$name $dur分钟',
                status: done
                    ? 'done'
                    : (now.hour >= 18 ? 'overdue' : 'pending'),
                iconColor: exIconColor,
                iconBg: exIconBg,
                onTap: () => pushRoute(ref, 'exercisePlan'),
              ),
            );
          }
        }
      },
      loading: () {
        hasExercise = true;
        tasks.add(
          _taskRow(
            context,
            Icons.directions_run,
            '运动',
            trailing: '正在加载运动计划',
            status: 'pending',
            iconColor: exIconColor,
            iconBg: exIconBg,
            onTap: () => pushRoute(ref, 'exercisePlan'),
          ),
        );
      },
      error: (_, _) {
        hasExercise = true;
        tasks.add(
          _taskRow(
            context,
            Icons.directions_run,
            '运动',
            trailing: '运动计划加载失败',
            status: 'overdue',
            iconColor: exIconColor,
            iconBg: exIconBg,
            onTap: () => pushRoute(ref, 'exercisePlan'),
          ),
        );
      },
    );
    if (!hasExercise) {
      tasks.add(
        _taskRow(
          context,
          Icons.directions_run,
          '运动',
          trailing: '暂无今日运动计划',
          status: 'pending',
          iconColor: exIconColor,
          iconBg: exIconBg,
          onTap: () => pushRoute(ref, 'exercisePlan'),
        ),
      );
    }

    // ── 3. 用药打卡 ──
    const medIconColor = Color(0xFFEC4899);
    const medIconBg = Color(0xFFFCE7F3);
    reminders.whenOrNull(
      data: (meds) {
        if (meds.isNotEmpty) {
          final overdueMeds = meds
              .where((m) => m['status'] == 'overdue')
              .toList();
          final upcomingMeds = meds
              .where((m) => m['status'] == 'upcoming')
              .toList();
          final takenMeds = meds.where((m) => m['status'] == 'taken').toList();
          // 未服/过期的在前面
          for (final m in [...overdueMeds, ...upcomingMeds]) {
            final name = m['name']?.toString() ?? '药品';
            final time = m['scheduledTime']?.toString() ?? '';
            final isOverdue = m['status'] == 'overdue';
            tasks.add(
              _taskRow(
                context,
                Icons.medication_rounded,
                name,
                trailing: '${isOverdue ? "❗过期" : "⏳待服"} $time',
                status: isOverdue ? 'overdue' : 'pending',
                iconColor: medIconColor,
                iconBg: medIconBg,
                onTap: () => pushRoute(ref, 'medCheckIn'),
              ),
            );
          }
          // 已服的合并显示
          if (takenMeds.isNotEmpty) {
            final names = takenMeds
                .map((m) => m['name']?.toString() ?? '药品')
                .join('、');
            tasks.add(
              _taskRow(
                context,
                Icons.check_circle,
                names,
                trailing: '已服用 (${takenMeds.length}项)',
                status: 'done',
                iconColor: medIconColor,
                iconBg: medIconBg,
              ),
            );
          }
        }
      },
    );
    final hasMeds =
        reminders.asData?.value != null && (reminders.asData!.value).isNotEmpty;
    if (!hasMeds) {
      tasks.add(
        _taskRow(
          context,
          Icons.medication_rounded,
          '用药打卡',
          trailing: '暂无用药提醒',
          status: 'pending',
          iconColor: medIconColor,
          iconBg: medIconBg,
          onTap: () => pushRoute(ref, 'medications'),
        ),
      );
    }

    return Container(
      margin: const EdgeInsets.only(bottom: 12),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(28),
        boxShadow: AppColors.cardShadow,
      ),
      clipBehavior: Clip.antiAlias,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            width: double.infinity,
            padding: const EdgeInsets.fromLTRB(16, 12, 16, 10),
            decoration: const BoxDecoration(
              gradient: LinearGradient(
                begin: Alignment.centerLeft,
                end: Alignment.centerRight,
                colors: [Color(0xFFE0C3FC), Color(0xFF8EC5FC)],
              ),
              borderRadius: BorderRadius.vertical(top: Radius.circular(28)),
            ),
            child: Row(
              children: [
                Container(
                  width: 28,
                  height: 28,
                  decoration: BoxDecoration(
                    color: Colors.white.withValues(alpha: 0.6),
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: const Icon(
                    Icons.health_and_safety,
                    size: 16,
                    color: AppColors.primary,
                  ),
                ),
                const SizedBox(width: 8),
                const Text(
                  '今日健康',
                  style: TextStyle(
                    fontSize: 15,
                    fontWeight: FontWeight.w600,
                    color: AppColors.textPrimary,
                  ),
                ),
                const Spacer(),
                Text(
                  '${now.month}月${now.day}日',
                  style: const TextStyle(
                    fontSize: 13,
                    color: AppColors.textSecondary,
                  ),
                ),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(14),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                if (tasks.isEmpty)
                  _taskRow(
                    context,
                    Icons.check_circle,
                    '今日暂无待办',
                    status: 'done',
                  )
                else
                  ...tasks,
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _taskRow(
    BuildContext context,
    IconData icon,
    String label, {
    String status = 'pending',
    String? trailing,
    VoidCallback? onTap,
    Color? iconColor,
    Color? iconBg,
  }) {
    final colors = {
      'done': AppTheme.success,
      'warning': AppColors.warning,
      'pending': AppColors.textHint,
      'overdue': AppTheme.error,
    };
    final icons = {
      'done': Icons.check_circle,
      'warning': Icons.warning,
      'pending': Icons.circle_outlined,
      'overdue': Icons.error,
    };
    final isOverdue = status == 'overdue';
    final ic = iconColor ?? AppTheme.primary;
    final ibg = iconBg ?? AppTheme.primaryLight;
    return Padding(
      padding: const EdgeInsets.only(bottom: 8),
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTap: onTap,
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
          decoration: BoxDecoration(
            color: isOverdue ? const Color(0xFFFFEBEE) : Colors.transparent,
            borderRadius: BorderRadius.circular(8),
          ),
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Container(
                width: 30,
                height: 30,
                decoration: BoxDecoration(
                  color: ibg,
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Icon(icon, size: 18, color: ic),
              ),
              const SizedBox(width: 10),
              Expanded(
                child: Text(
                  trailing ?? label,
                  style: const TextStyle(
                    fontSize: 16,
                    color: AppColors.textPrimary,
                  ),
                ),
              ),
              Icon(
                icons[status] ?? Icons.circle_outlined,
                size: 21,
                color: colors[status] ?? Colors.grey,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _AgentMark extends StatelessWidget {
  final IconData icon;
  final _AgentColors colors;
  const _AgentMark({required this.icon, required this.colors});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 64,
      height: 64,
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: colors.gradient,
          begin: colors.verticalGradient
              ? Alignment.topCenter
              : Alignment.topLeft,
          end: colors.verticalGradient
              ? Alignment.bottomCenter
              : Alignment.bottomRight,
        ),
        borderRadius: BorderRadius.circular(colors.verticalGradient ? 18 : 20),
        boxShadow: [
          BoxShadow(
            color: colors.accent.withValues(alpha: 0.18),
            blurRadius: 18,
            offset: const Offset(0, 8),
          ),
        ],
      ),
      child: Center(child: Icon(icon, size: 32, color: Colors.white)),
    );
  }
}

class _LinearAccentMark extends StatelessWidget {
  final _AgentColors colors;
  const _LinearAccentMark({required this.colors});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 86,
      height: 8,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(999),
        gradient: LinearGradient(
          colors: colors.gradient
              .map((color) => color.withValues(alpha: 0.34))
              .toList(),
        ),
      ),
    );
  }
}

class _MiniSignalStrip extends StatelessWidget {
  final _AgentColors colors;
  const _MiniSignalStrip({required this.colors});

  @override
  Widget build(BuildContext context) {
    final bars = [12.0, 20.0, 14.0, 26.0, 16.0, 22.0, 12.0];
    return Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        for (var i = 0; i < bars.length; i++) ...[
          Container(
            width: 4,
            height: bars[i],
            decoration: BoxDecoration(
              color: colors.accent.withValues(alpha: i.isEven ? 0.34 : 0.18),
              borderRadius: BorderRadius.circular(99),
            ),
          ),
          if (i != bars.length - 1) const SizedBox(width: 4),
        ],
      ],
    );
  }
}

typedef _AgentIcon = IconData;

class _AgentColors {
  final List<Color> gradient;
  final Color bg;
  final Color border;
  final Color iconBg;
  final Color accent;
  final bool verticalGradient;
  const _AgentColors({
    required this.gradient,
    required this.bg,
    required this.border,
    required this.iconBg,
    required this.accent,
    this.verticalGradient = false,
  });
}

class _AgentAction {
  final String label;
  final IconData icon;
  final bool isWide;
  final String? route;
  final String? action;

  const _AgentAction({
    required this.label,
    required this.icon,
    this.isWide = false,
    this.route,
    this.action,
  });
}

class _ConfirmField {
  final String label;
  final String value;
  const _ConfirmField({
    required this.label,
    required this.value,
  });
}

final _agentActions = <ActiveAgent, List<_AgentAction>>{
  ActiveAgent.health: [
    _AgentAction(
      label: '健康概览',
      icon: Icons.trending_up,
      isWide: true,
      route: 'trend',
    ),
    _AgentAction(
      label: '蓝牙录入',
      icon: Icons.bluetooth,
      isWide: true,
      route: 'devices',
    ),
  ],
  ActiveAgent.diet: [
    _AgentAction(
      label: '拍照识别',
      icon: Icons.camera_alt_outlined,
      isWide: true,
      action: 'pickFoodCamera',
    ),
    _AgentAction(
      label: '上传照片',
      icon: Icons.photo_library_outlined,
      isWide: true,
      action: 'pickFoodGallery',
    ),
  ],
  ActiveAgent.medication: [
    _AgentAction(
      label: '用药管理',
      icon: Icons.medication_liquid_outlined,
      isWide: true,
      route: 'medications',
    ),
    _AgentAction(label: '服药打卡', icon: Icons.check_circle_outline, isWide: true),
  ],
  ActiveAgent.consultation: [],
  ActiveAgent.report: [
    _AgentAction(
      label: '上传报告',
      icon: Icons.upload_file_outlined,
      isWide: true,
      route: 'reports',
    ),
    _AgentAction(
      label: '查看历史',
      icon: Icons.history_outlined,
      isWide: true,
      route: 'reports',
    ),
  ],
  ActiveAgent.exercise: [
    _AgentAction(
      label: '查看计划',
      icon: Icons.calendar_month_outlined,
      isWide: true,
      route: 'exercisePlan',
    ),
    _AgentAction(
      label: '新建计划',
      icon: Icons.add_task_outlined,
      isWide: true,
      route: 'exerciseCreate',
    ),
  ],
};

extension _AgentActionsExt on ActiveAgent {
  List<_AgentAction> get actions =>
      _agentActions[this] ??
      [const _AgentAction(label: '开始对话', icon: Icons.chat_outlined)];
}

// ════════════════════════════════════════════════════════════════
// 可展开的 AI 建议小组件
// ════════════════════════════════════════════════════════════════

class _ExpandableAdvice extends StatefulWidget {
  final String advice;
  const _ExpandableAdvice({required this.advice});

  @override
  State<_ExpandableAdvice> createState() => _ExpandableAdviceState();
}

class _ExpandableAdviceState extends State<_ExpandableAdvice> {
  bool _expanded = false;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => setState(() => _expanded = !_expanded),
      child: Container(
        width: double.infinity,
        padding: const EdgeInsets.all(14),
        decoration: BoxDecoration(
          color: AppColors.backgroundSecondary,
          borderRadius: BorderRadius.circular(12),
          border: Border.all(color: const Color(0xFFE8E4FF), width: 0.8),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                const Icon(
                  Icons.lightbulb_outline,
                  size: 19,
                  color: AppTheme.primary,
                ),
                const SizedBox(width: 6),
                const Text(
                  'AI 建议',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w600,
                    color: AppTheme.primary,
                  ),
                ),
                const Spacer(),
                Icon(
                  _expanded
                      ? Icons.keyboard_arrow_up
                      : Icons.keyboard_arrow_down,
                  size: 21,
                  color: AppColors.textHint,
                ),
              ],
            ),
            if (_expanded) ...[
              const SizedBox(height: 10),
              Text(
                widget.advice,
                style: const TextStyle(
                  fontSize: 16,
                  color: Color(0xFF555555),
                  height: 1.6,
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }
}
