import 'dart:math';

import 'package:fl_chart/fl_chart.dart';
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_theme.dart';
import '../../core/navigation_provider.dart';
import '../../providers/auth_provider.dart';
import '../../widgets/app_toast.dart';
import '../../providers/data_providers.dart';
import '../../widgets/common_widgets.dart';
import '../../widgets/app_empty_state.dart';

const String defaultTrendMetricType = 'blood_pressure';

const Set<String> supportedTrendMetricTypes = {
  'blood_pressure',
  'heart_rate',
  'glucose',
  'spo2',
  'weight',
};

class _TrendColors {
  _TrendColors._();

  static const bloodPressure = Color(0xFFD45B68);
  static const heartRate = Color(0xFFD97757);
  static const glucose = Color(0xFF4F6EF7);
  static const spo2 = Color(0xFF168F7A);
  static const weight = Color(0xFF7559C7);
  static const systolic = bloodPressure;
  static const diastolic = Color(0xFF3B82F6);
}

String normalizeTrendMetricType(String? metricType) {
  if (metricType == null) return defaultTrendMetricType;
  return supportedTrendMetricTypes.contains(metricType)
      ? metricType
      : defaultTrendMetricType;
}

List<Map<String, dynamic>> filterTrendRecordsForPeriod(
  List<Map<String, dynamic>> records,
  int days,
  DateTime now,
) {
  final today = DateTime(now.year, now.month, now.day);
  final start = today.subtract(Duration(days: days - 1));
  return records.where((record) {
    final date = record['date'];
    return date is DateTime && !date.isBefore(start);
  }).toList();
}

String formatTrendNumber(num? value) {
  if (value == null) return '--';
  final number = value.toDouble();
  return number == number.roundToDouble()
      ? number.toInt().toString()
      : number.toStringAsFixed(1);
}

String trendStatusLabel(Map<String, dynamic> record, String metricType) {
  if (record['isAbnormal'] != true) return '';
  if (metricType != 'blood_pressure') return '异常';

  final systolic = (record['systolic'] as num?)?.toDouble();
  final diastolic = (record['diastolic'] as num?)?.toDouble();
  if (systolic != null && systolic >= 140) return '收缩压偏高';
  if (diastolic != null && diastolic >= 90) return '舒张压偏高';
  if ((systolic != null && systolic < 90) ||
      (diastolic != null && diastolic < 60)) {
    return '血压偏低';
  }
  return '血压异常';
}

/// 健康概览趋势页 — 五大指标合到一个页面
class TrendPage extends ConsumerStatefulWidget {
  final String? metricType; // 可选初始选中指标
  const TrendPage({super.key, this.metricType});

  @override
  ConsumerState<TrendPage> createState() => _TrendPageState();
}

class _TrendPageState extends ConsumerState<TrendPage> {
  String _selected = defaultTrendMetricType;
  List<Map<String, dynamic>> _allRecords = [];
  List<Map<String, dynamic>> _filtered = [];
  Set<String> _failedTypes = {};
  bool _loading = true;
  int _periodDays = 7;
  int? _selectedIdx; // 当前选中的数据点（_filtered 索引），null = 未选中

  /// 计算"好看"的坐标轴步长，最小为 1（保证标签都是整数）。
  /// 目标 3 段 = 4 个标签；若吸附后超过 3 段，自动放大步长。
  double _niceStep(double range) {
    if (range <= 0) return 1;
    final target = range / 3;
    if (target < 1) return 1;
    final magnitude = pow(10, (log(target) / log(10)).floor()).toDouble();
    final normalized = target / magnitude;
    double nice;
    if (normalized <= 1) {
      nice = 1;
    } else if (normalized <= 2) {
      nice = 2;
    } else if (normalized <= 5) {
      nice = 5;
    } else {
      nice = 10;
    }
    return nice * magnitude;
  }

  /// 步长过大时，跳到下一个"好看"的步长（1→2→5→10→20→50…）
  double _bumpStep(double step) {
    final magnitude = pow(10, (log(step) / log(10)).floor()).toDouble();
    final normalized = step / magnitude;
    if (normalized < 1.5) return 2 * magnitude;
    if (normalized < 4) return 5 * magnitude;
    return 10 * magnitude;
  }

  static const _metrics = [
    {
      'key': 'blood_pressure',
      'label': '血压',
      'color': _TrendColors.bloodPressure,
      'icon': LucideIcons.gauge,
    },
    {
      'key': 'heart_rate',
      'label': '心率',
      'color': _TrendColors.heartRate,
      'icon': LucideIcons.heartPulse,
    },
    {
      'key': 'glucose',
      'label': '血糖',
      'color': _TrendColors.glucose,
      'icon': LucideIcons.droplet,
    },
    {
      'key': 'spo2',
      'label': '血氧',
      'color': _TrendColors.spo2,
      'icon': LucideIcons.wind,
    },
    {
      'key': 'weight',
      'label': '体重',
      'color': _TrendColors.weight,
      'icon': LucideIcons.scale,
    },
  ];

  static const _units = {
    'blood_pressure': 'mmHg',
    'heart_rate': 'bpm',
    'glucose': 'mmol/L',
    'spo2': '%',
    'weight': 'kg',
  };

  static const _names = {
    'blood_pressure': '血压',
    'heart_rate': '心率',
    'glucose': '血糖',
    'spo2': '血氧',
    'weight': '体重',
  };

  String get _unit => _units[_selected] ?? '';
  String get _name => _names[_selected] ?? '';
  bool get _isBP => _selected == 'blood_pressure';
  String get _selectedApiType => _apiTypeForMetric(_selected);
  List<Map<String, dynamic>> get _chartRecords =>
      filterTrendRecordsForPeriod(_filtered, _periodDays, DateTime.now());
  Map<String, dynamic>? get _latestRecord =>
      _filtered.isEmpty ? null : _filtered.last;
  Color get _color =>
      _metrics.firstWhere(
            (m) => m['key'] == normalizeTrendMetricType(_selected),
          )['color']
          as Color;

  @override
  void initState() {
    super.initState();
    _selected = normalizeTrendMetricType(widget.metricType);
    _loadAll();
  }

  Future<void> _loadAll() async {
    setState(() => _loading = true);
    try {
      final api = ref.read(apiClientProvider);
      final types = ['BloodPressure', 'HeartRate', 'Glucose', 'SpO2', 'Weight'];
      final failedTypes = <String>{};
      final groups = await Future.wait(
        types.map((type) async {
          try {
            final res = await api.get(
              '/api/health-records/trend',
              queryParameters: {'type': type, 'period': 365},
            );
            final list =
                (res.data['data'] as List?)?.cast<Map<String, dynamic>>() ?? [];
            return list.map((record) {
              return <String, dynamic>{
                'id': record['id'],
                'type': type,
                'date':
                    DateTime.tryParse(
                      record['recordedAt']?.toString() ?? '',
                    )?.toLocal() ??
                    DateTime.now(),
                'systolic': record['systolic'],
                'diastolic': record['diastolic'],
                'value': record['value'],
                'unit': record['unit'] ?? '',
                'isAbnormal': record['isAbnormal'] == true,
              };
            }).toList();
          } catch (e) {
            failedTypes.add(type);
            debugPrint('[Trend] 加载 $type 趋势失败: $e');
            return <Map<String, dynamic>>[];
          }
        }),
      );
      final all = groups.expand((group) => group).toList();
      all.sort(
        (a, b) => (b['date'] as DateTime).compareTo(a['date'] as DateTime),
      );
      if (mounted) {
        setState(() {
          _allRecords = all;
          _failedTypes = failedTypes;
          _loading = false;
        });
        _filter();
      }
    } catch (_) {
      if (mounted) setState(() => _loading = false);
    }
  }

  void _filter() {
    setState(() {
      _filtered = _allRecords
          .where((record) => record['type'] == _selectedApiType)
          .toList();
      _filtered.sort(
        (a, b) => (a['date'] as DateTime).compareTo(b['date'] as DateTime),
      );
    });
  }

  void _switchMetric(String key) {
    setState(() {
      _selected = key;
      _periodDays = key == 'weight' ? 30 : 7;
      _selectedIdx = null;
    });
    _filter();
  }

  String _apiTypeForMetric(String key) {
    return switch (key) {
      'blood_pressure' => 'BloodPressure',
      'heart_rate' => 'HeartRate',
      'glucose' => 'Glucose',
      'spo2' => 'SpO2',
      _ => 'Weight',
    };
  }

  // ---- 手动录入 ----
  void _showAddDialog() {
    final ctrl1 = TextEditingController();
    final ctrl2 = TextEditingController();
    showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      shape: const RoundedRectangleBorder(
        borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
      ),
      builder: (ctx) => Padding(
        padding: EdgeInsets.only(
          bottom: MediaQuery.of(ctx).viewInsets.bottom,
          left: 20,
          right: 20,
          top: 20,
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              '录入$_name',
              style: const TextStyle(fontSize: 21, fontWeight: FontWeight.w700),
            ),
            const SizedBox(height: 16),
            if (_isBP) ...[
              Row(
                children: [
                  Expanded(
                    child: TextField(
                      controller: ctrl1,
                      keyboardType: TextInputType.number,
                      decoration: const InputDecoration(
                        labelText: '收缩压 (mmHg)',
                        border: OutlineInputBorder(),
                      ),
                    ),
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: TextField(
                      controller: ctrl2,
                      keyboardType: TextInputType.number,
                      decoration: const InputDecoration(
                        labelText: '舒张压 (mmHg)',
                        border: OutlineInputBorder(),
                      ),
                    ),
                  ),
                ],
              ),
            ] else
              TextField(
                controller: ctrl1,
                keyboardType: TextInputType.number,
                decoration: InputDecoration(
                  labelText: '$_name ($_unit)',
                  border: const OutlineInputBorder(),
                ),
              ),
            const SizedBox(height: 16),
            SizedBox(
              width: double.infinity,
              child: AppGradientOutlineButton(
                label: '确认录入',
                onPressed: () async {
                  final v1 = double.tryParse(ctrl1.text.trim());
                  final v2 = _isBP ? double.tryParse(ctrl2.text.trim()) : null;
                  if (v1 == null || (_isBP && v2 == null)) {
                    AppToast.show(
                      ctx,
                      _isBP ? '请完整填写收缩压和舒张压' : '请输入有效的$_name数值',
                      type: AppToastType.error,
                    );
                    return;
                  }
                  if (_isBP &&
                      (v1 < 50 ||
                          v1 > 250 ||
                          v2! < 30 ||
                          v2 > 150 ||
                          v1 <= v2)) {
                    AppToast.show(
                      ctx,
                      '请检查血压数值，收缩压应高于舒张压',
                      type: AppToastType.error,
                    );
                    return;
                  }
                  try {
                    final api = ref.read(apiClientProvider);
                    final body = <String, dynamic>{
                      'type': _selectedApiType,
                      'source': 'Manual',
                      'recordedAt': DateTime.now().toUtc().toIso8601String(),
                      'unit': _unit,
                    };
                    if (_isBP) {
                      body['systolic'] = v1.toInt();
                      body['diastolic'] = v2!.toInt();
                    } else {
                      body['value'] = v1;
                    }
                    await api.post('/api/health-records', data: body);
                    if (!ctx.mounted || !mounted) {
                      return;
                    }
                    Navigator.pop(ctx);
                    ref.invalidate(latestHealthProvider);
                    _loadAll();
                  } catch (_) {
                    if (!mounted) {
                      return;
                    }
                    AppToast.show(
                      context,
                      '录入失败，请检查数值或网络后重试',
                      type: AppToastType.error,
                    );
                  }
                },
              ),
            ),
            const SizedBox(height: 20),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return GradientScaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => popRoute(ref),
        ),
        title: const Text('健康概览'),
        centerTitle: true,
      ),
      floatingActionButton: AppCreateFab(
        tooltip: '添加健康记录',
        onPressed: _showAddDialog,
      ),
      body: _loading
          ? const Center(
              child: CircularProgressIndicator(color: AppTheme.primary),
            )
          : RefreshIndicator(
              onRefresh: _loadAll,
              child: SingleChildScrollView(
                physics: const AlwaysScrollableScrollPhysics(),
                padding: const EdgeInsets.all(14),
                child: Column(
                  children: [
                    _buildMetricTabs(),
                    const SizedBox(height: 16),
                    if (_latestRecord != null) ...[
                      _buildLatestSummary(),
                      const SizedBox(height: 16),
                    ],
                    _buildPeriodSelector(),
                    const SizedBox(height: 12),
                    _buildChart(),
                    if (_chartRecords.isNotEmpty) ...[
                      const SizedBox(height: 12),
                      _buildStatistics(),
                    ],
                    const SizedBox(height: 24),
                    _buildHistory(),
                    const SizedBox(height: 80),
                  ],
                ),
              ),
            ),
    );
  }

  // ---- 指标选择标签 ----
  Widget _buildMetricTabs() {
    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Row(
        children: _metrics.map((m) {
          final key = m['key'] as String;
          final color = m['color'] as Color;
          final sel = _selected == key;
          return GestureDetector(
            onTap: () => _switchMetric(key),
            child: Container(
              margin: const EdgeInsets.only(right: 8),
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              decoration: BoxDecoration(
                color: sel ? AppColors.primarySoft : Colors.white,
                borderRadius: AppRadius.xlBorder,
                border: Border.all(
                  color: sel ? AppColors.primary : AppColors.borderLight,
                ),
              ),
              child: Row(
                mainAxisSize: MainAxisSize.min,
                children: [
                  Icon(
                    m['icon'] as IconData,
                    size: 17,
                    color: sel ? AppColors.primaryDark : color,
                  ),
                  const SizedBox(width: 6),
                  Text(
                    m['label'] as String,
                    style: TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w700,
                      color: sel
                          ? AppColors.primaryDark
                          : AppColors.textSecondary,
                    ),
                  ),
                ],
              ),
            ),
          );
        }).toList(),
      ),
    );
  }

  Widget _buildLatestSummary() {
    final record = _latestRecord!;
    final date = record['date'] as DateTime;
    final status = trendStatusLabel(record, _selected);
    final abnormal = status.isNotEmpty;
    return Container(
      width: double.infinity,
      padding: AppSpacing.panel,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: AppRadius.lgBorder,
      ),
      child: Row(
        children: [
          Container(
            width: 48,
            height: 48,
            decoration: BoxDecoration(
              color: _color.withValues(alpha: 0.10),
              borderRadius: AppRadius.mdBorder,
            ),
            child: Icon(_getMetricIcon(_selected), color: _color, size: 25),
          ),
          const SizedBox(width: 14),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '最新$_name',
                  style: const TextStyle(
                    fontSize: 15,
                    fontWeight: FontWeight.w600,
                    color: AppColors.textSecondary,
                  ),
                ),
                const SizedBox(height: 4),
                Wrap(
                  crossAxisAlignment: WrapCrossAlignment.end,
                  spacing: 6,
                  children: [
                    Text(
                      _displayValue(record),
                      style: const TextStyle(
                        fontSize: 32,
                        fontWeight: FontWeight.w600,
                        color: AppColors.textPrimary,
                        height: 1.05,
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(bottom: 3),
                      child: Text(
                        _unit,
                        style: const TextStyle(
                          fontSize: 15,
                          color: AppColors.textHint,
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
          Column(
            crossAxisAlignment: CrossAxisAlignment.end,
            children: [
              Text(
                abnormal ? status : '正常',
                style: TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w700,
                  color: abnormal ? AppColors.errorText : AppColors.successText,
                ),
              ),
              const SizedBox(height: 6),
              Text(
                _formatRecordTime(date),
                style: const TextStyle(fontSize: 13, color: AppColors.textHint),
              ),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildPeriodSelector() {
    return Container(
      padding: const EdgeInsets.all(3),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: AppRadius.mdBorder,
      ),
      child: Row(
        children: [
          for (final days in const [7, 30, 90])
            Expanded(
              child: InkWell(
                onTap: () => setState(() {
                  _periodDays = days;
                  _selectedIdx = null;
                }),
                borderRadius: AppRadius.smBorder,
                child: Container(
                  height: 38,
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                    color: _periodDays == days
                        ? AppColors.primaryLight
                        : Colors.transparent,
                    borderRadius: AppRadius.smBorder,
                  ),
                  child: Text(
                    '$days天',
                    style: TextStyle(
                      fontSize: 15,
                      fontWeight: FontWeight.w700,
                      color: _periodDays == days
                          ? AppColors.primaryDark
                          : AppColors.textSecondary,
                    ),
                  ),
                ),
              ),
            ),
        ],
      ),
    );
  }

  Widget _buildStatistics() {
    final records = _chartRecords;
    final values = records
        .map((record) => (record['value'] as num?)?.toDouble())
        .whereType<double>()
        .toList();
    String average;
    String highest;
    if (_isBP) {
      final systolic = records
          .map((record) => (record['systolic'] as num?)?.toDouble())
          .whereType<double>()
          .toList();
      final diastolic = records
          .map((record) => (record['diastolic'] as num?)?.toDouble())
          .whereType<double>()
          .toList();
      average = systolic.isEmpty || diastolic.isEmpty
          ? '--'
          : '${(systolic.reduce((a, b) => a + b) / systolic.length).round()}/${(diastolic.reduce((a, b) => a + b) / diastolic.length).round()}';
      final highestRecord = records
          .where((record) {
            return record['systolic'] is num && record['diastolic'] is num;
          })
          .fold<Map<String, dynamic>?>(null, (current, record) {
            if (current == null) return record;
            final currentValue = (current['systolic'] as num).toDouble();
            final recordValue = (record['systolic'] as num).toDouble();
            return recordValue > currentValue ? record : current;
          });
      highest = highestRecord == null ? '--' : _displayValue(highestRecord);
    } else {
      average = values.isEmpty
          ? '--'
          : formatTrendNumber(values.reduce((a, b) => a + b) / values.length);
      highest = values.isEmpty ? '--' : formatTrendNumber(values.reduce(max));
    }

    return Container(
      padding: const EdgeInsets.symmetric(vertical: 14),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: AppRadius.lgBorder,
      ),
      child: Row(
        children: [
          _StatisticItem(label: '平均', value: average, unit: _unit),
          const SizedBox(height: 46, child: VerticalDivider(width: 1)),
          _StatisticItem(label: '最高', value: highest, unit: _unit),
          const SizedBox(height: 46, child: VerticalDivider(width: 1)),
          _StatisticItem(label: '记录', value: '${records.length}', unit: '次'),
        ],
      ),
    );
  }

  String _displayValue(Map<String, dynamic> record) {
    if (_isBP) {
      return '${formatTrendNumber(record['systolic'] as num?)}/${formatTrendNumber(record['diastolic'] as num?)}';
    }
    return formatTrendNumber(record['value'] as num?);
  }

  String _formatRecordTime(DateTime date) {
    final now = DateTime.now();
    final sameDay =
        now.year == date.year && now.month == date.month && now.day == date.day;
    final time =
        '${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}';
    return sameDay ? '今天 $time' : '${date.month}月${date.day}日 $time';
  }

  // ---- 趋势图 ----
  Widget _buildChart() {
    if (_failedTypes.contains(_selectedApiType)) {
      return Container(
        height: 220,
        alignment: Alignment.center,
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: AppRadius.lgBorder,
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Icon(Icons.cloud_off_outlined, color: AppColors.textHint),
            const SizedBox(height: 8),
            Text('$_name数据加载失败'),
            TextButton.icon(
              onPressed: _loadAll,
              icon: const Icon(Icons.refresh_rounded, size: 18),
              label: const Text('重新加载'),
            ),
          ],
        ),
      );
    }
    final records = _chartRecords;
    if (records.isEmpty) {
      return Container(
        height: 220,
        decoration: BoxDecoration(
          color: Colors.white,
          borderRadius: AppRadius.lgBorder,
        ),
        child: AppEmptyState(
          icon: _getMetricIcon(_selected),
          iconColor: _color,
          title: '近$_periodDays天没有$_name数据',
          subtitle: '点击右下角 + 手动录入',
          padding: const EdgeInsets.all(20),
        ),
      );
    }

    final spots = <FlSpot>[];
    final diastolicSpots = <FlSpot>[];
    double minV = double.infinity, maxV = double.negativeInfinity;
    for (int i = 0; i < records.length; i++) {
      final r = records[i];
      final v = _isBP
          ? (r['systolic'] as num?)?.toDouble()
          : (r['value'] as num?)?.toDouble();
      if (v == null) continue;
      if (v < minV) minV = v;
      if (v > maxV) maxV = v;
      spots.add(FlSpot(i.toDouble(), v));
      if (_isBP) {
        final diastolic = (r['diastolic'] as num?)?.toDouble();
        if (diastolic != null) {
          minV = min(minV, diastolic);
          maxV = max(maxV, diastolic);
          diastolicSpots.add(FlSpot(i.toDouble(), diastolic));
        }
      }
    }

    if (spots.isEmpty) return const SizedBox.shrink();
    final range = maxV - minV;
    final padding = range * 0.15;
    if (padding < 1) {
      minV -= 5;
      maxV += 5;
    } else {
      minV -= padding;
      maxV += padding;
    }

    // Y 轴：吸附到"好看"的整数刻度，标签全部为整数，最多 4 个（3 段）
    var yStep = _niceStep(maxV - minV);
    minV = (minV / yStep).floor() * yStep;
    maxV = (maxV / yStep).ceil() * yStep;
    while ((maxV - minV) / yStep > 3) {
      yStep = _bumpStep(yStep);
      minV = (minV / yStep).floor() * yStep;
      maxV = (maxV / yStep).ceil() * yStep;
    }

    // X 轴刻度间隔：日标签短，可以排密一点
    final xInterval = spots.length > 60
        ? 5.0
        : spots.length > 30
        ? 2.0
        : 1.0;

    return Container(
      padding: const EdgeInsets.fromLTRB(8, 20, 16, 12),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: AppRadius.lgBorder,
      ),
      child: Column(
        children: [
          Row(
            children: [
              const SizedBox(width: 8),
              Text(
                _name,
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.w600,
                  color: _color,
                ),
              ),
              const SizedBox(width: 6),
              Text(
                '趋势 (${records.length}条)',
                style: const TextStyle(
                  fontSize: 15,
                  color: AppColors.textSecondary,
                ),
              ),
              const Spacer(),
              Text(
                '单位: $_unit',
                style: const TextStyle(fontSize: 14, color: AppColors.textHint),
              ),
            ],
          ),
          if (_isBP) ...[
            const SizedBox(height: 8),
            const Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                _ChartLegend(color: _TrendColors.systolic, label: '收缩压'),
                SizedBox(width: 16),
                _ChartLegend(color: _TrendColors.diastolic, label: '舒张压'),
              ],
            ),
          ],
          const SizedBox(height: 10),
          SizedBox(
            height: 200,
            child: LayoutBuilder(
              builder: (context, constraints) {
                final chartWidth = constraints.maxWidth;
                final paintWidth = chartWidth - 40.0; // 减左侧轴
                final paintHeight = 200.0 - 36.0; // 减底部轴
                // 计算选中点的像素位置
                Offset? tooltipPos;
                String? tooltipText1;
                String? tooltipText2;
                if (_selectedIdx != null &&
                    _selectedIdx! >= 0 &&
                    _selectedIdx! < records.length) {
                  final r = records[_selectedIdx!];
                  final v = _isBP
                      ? (r['systolic'] as num?)?.toDouble()
                      : (r['value'] as num?)?.toDouble();
                  if (v != null && spots.length > 1) {
                    final px =
                        40.0 +
                        (_selectedIdx! / (spots.length - 1)) * paintWidth;
                    final py = paintHeight * (1 - (v - minV) / (maxV - minV));
                    final d = r['date'] as DateTime;
                    tooltipPos = Offset(px, py);
                    tooltipText1 =
                        '${d.month}/${d.day} ${d.hour}:${d.minute.toString().padLeft(2, '0')}';
                    tooltipText2 = _isBP
                        ? '${r['systolic']}/${r['diastolic']} $_unit'
                        : '$v $_unit';
                  }
                }
                return Stack(
                  clipBehavior: Clip.none,
                  children: [
                    LineChart(
                      LineChartData(
                        minX: 0,
                        maxX: max(1, spots.length - 1).toDouble(),
                        minY: minV,
                        maxY: maxV,
                        gridData: FlGridData(
                          show: true,
                          drawVerticalLine: false,
                          horizontalInterval: yStep,
                          getDrawingHorizontalLine: (_) => const FlLine(
                            color: AppColors.divider,
                            strokeWidth: 0.8,
                            dashArray: [4, 4],
                          ),
                        ),
                        borderData: FlBorderData(show: false),
                        titlesData: FlTitlesData(
                          leftTitles: AxisTitles(
                            sideTitles: SideTitles(
                              showTitles: true,
                              reservedSize: 40,
                              interval: yStep,
                              getTitlesWidget: (v, meta) => Padding(
                                padding: const EdgeInsets.only(right: 6),
                                child: Text(
                                  v.toStringAsFixed(0),
                                  style: const TextStyle(
                                    fontSize: 12,
                                    color: AppColors.textHint,
                                    fontWeight: FontWeight.w500,
                                  ),
                                ),
                              ),
                            ),
                          ),
                          bottomTitles: AxisTitles(
                            sideTitles: SideTitles(
                              showTitles: true,
                              reservedSize: 36,
                              interval: xInterval,
                              getTitlesWidget: (v, meta) {
                                final idx = v.toInt();
                                if (idx < 0 || idx >= records.length) {
                                  return const SizedBox.shrink();
                                }
                                return Padding(
                                  padding: const EdgeInsets.only(top: 8),
                                  child: Text(
                                    _chartAxisLabel(records, idx),
                                    style: const TextStyle(
                                      fontSize: 11,
                                      color: AppColors.textHint,
                                      fontWeight: FontWeight.w500,
                                    ),
                                  ),
                                );
                              },
                            ),
                          ),
                          topTitles: const AxisTitles(
                            sideTitles: SideTitles(showTitles: false),
                          ),
                          rightTitles: const AxisTitles(
                            sideTitles: SideTitles(showTitles: false),
                          ),
                        ),
                        lineBarsData: [
                          LineChartBarData(
                            spots: spots,
                            isCurved: false,
                            color: _color,
                            barWidth: 2.5,
                            isStrokeCapRound: true,
                            dotData: FlDotData(
                              show: spots.length <= 30,
                              getDotPainter: (spot, _, _, _) {
                                final isSelected =
                                    spot.x.toInt() == _selectedIdx;
                                if (isSelected) {
                                  return FlDotCirclePainter(
                                    radius: 5.5,
                                    color: _color,
                                    strokeWidth: 2.5,
                                    strokeColor: Colors.white,
                                  );
                                }
                                return FlDotCirclePainter(
                                  radius: 3.5,
                                  color: Colors.white,
                                  strokeWidth: 2,
                                  strokeColor: _color,
                                );
                              },
                            ),
                            belowBarData: BarAreaData(show: false),
                          ),
                          if (_isBP && diastolicSpots.isNotEmpty)
                            LineChartBarData(
                              spots: diastolicSpots,
                              isCurved: false,
                              color: _TrendColors.diastolic,
                              barWidth: 2.5,
                              isStrokeCapRound: true,
                              dotData: FlDotData(
                                show: diastolicSpots.length <= 30,
                                getDotPainter: (spot, _, _, _) =>
                                    FlDotCirclePainter(
                                      radius: spot.x.toInt() == _selectedIdx
                                          ? 5.5
                                          : 3.5,
                                      color: Colors.white,
                                      strokeWidth: 2,
                                      strokeColor: _TrendColors.diastolic,
                                    ),
                              ),
                              belowBarData: BarAreaData(show: false),
                            ),
                        ],
                        lineTouchData: LineTouchData(
                          handleBuiltInTouches: false,
                          touchCallback: (event, response) {
                            if (event is FlTapUpEvent) {
                              final spots = response?.lineBarSpots;
                              if (spots != null && spots.isNotEmpty) {
                                final idx = spots.first.x.toInt();
                                setState(
                                  () => _selectedIdx = (_selectedIdx == idx)
                                      ? null
                                      : idx,
                                );
                              } else {
                                setState(() => _selectedIdx = null);
                              }
                            }
                          },
                        ),
                      ),
                      duration: Duration.zero,
                    ),
                    if (tooltipPos != null)
                      Positioned(
                        left: tooltipPos.dx.clamp(60.0, chartWidth - 60.0),
                        top: tooltipPos.dy - 56,
                        child: FractionalTranslation(
                          translation: const Offset(-0.5, 0),
                          child: Container(
                            padding: const EdgeInsets.symmetric(
                              horizontal: 10,
                              vertical: 6,
                            ),
                            decoration: BoxDecoration(
                              color: Colors.white,
                              borderRadius: AppRadius.xsBorder,
                              border: Border.all(
                                color: _color.withValues(alpha: 0.35),
                              ),
                              boxShadow: [
                                BoxShadow(
                                  color: const Color(
                                    0xFF101828,
                                  ).withValues(alpha: 0.14),
                                  blurRadius: 16,
                                  offset: const Offset(0, 6),
                                ),
                              ],
                            ),
                            child: Column(
                              mainAxisSize: MainAxisSize.min,
                              children: [
                                Text(
                                  tooltipText1!,
                                  style: const TextStyle(
                                    fontSize: 11,
                                    color: AppColors.textHint,
                                    fontWeight: FontWeight.w500,
                                  ),
                                ),
                                const SizedBox(height: 2),
                                Text(
                                  tooltipText2!,
                                  style: TextStyle(
                                    fontSize: 15,
                                    color: _color,
                                    fontWeight: FontWeight.w700,
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                  ],
                );
              },
            ),
          ),
        ],
      ),
    );
  }

  String _chartAxisLabel(List<Map<String, dynamic>> records, int index) {
    final date = records[index]['date'] as DateTime;
    final sameDayCount = records.where((record) {
      final other = record['date'] as DateTime;
      return other.year == date.year &&
          other.month == date.month &&
          other.day == date.day;
    }).length;
    if (sameDayCount > 1) {
      return '${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}';
    }
    return '${date.month}-${date.day}';
  }

  // ---- 历史记录列表 ----
  Widget _buildHistory() {
    if (_filtered.isEmpty) return const SizedBox.shrink();
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            const Text(
              '录入记录',
              style: TextStyle(fontSize: 19, fontWeight: FontWeight.w700),
            ),
            const Spacer(),
            Text(
              '最近${min(30, _filtered.length)}条',
              style: const TextStyle(
                fontSize: 16,
                color: AppColors.textSecondary,
              ),
            ),
          ],
        ),
        const SizedBox(height: 10),
        Container(
          clipBehavior: Clip.antiAlias,
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: AppRadius.xlBorder,
          ),
          child: Column(
            children: [
              ..._filtered.reversed.take(30).toList().asMap().entries.map((
                entry,
              ) {
                final r = entry.value;
                final isLast =
                    entry.key == _filtered.reversed.take(30).length - 1;
                final date = r['date'] as DateTime;
                final abnormal = r['isAbnormal'] == true;
                final id = r['id']?.toString() ?? '';
                final chartRecords = _chartRecords;
                final selectedId =
                    _selectedIdx != null &&
                        _selectedIdx! >= 0 &&
                        _selectedIdx! < chartRecords.length
                    ? chartRecords[_selectedIdx!]['id']?.toString()
                    : null;
                final isSelected = selectedId == id;
                final display = _displayValue(r);
                final status = trendStatusLabel(r, _selected);
                return Dismissible(
                  key: ValueKey('$id-${date.microsecondsSinceEpoch}'),
                  direction: DismissDirection.endToStart,
                  background: Container(
                    color: AppColors.error,
                    alignment: Alignment.centerRight,
                    padding: const EdgeInsets.only(right: 20),
                    child: const Icon(
                      Icons.delete_outline,
                      color: Colors.white,
                    ),
                  ),
                  confirmDismiss: (_) async {
                    try {
                      final api = ref.read(apiClientProvider);
                      await api.delete('/api/health-records/$id');
                      return true;
                    } catch (_) {
                      if (mounted) {
                        AppToast.show(
                          context,
                          '删除失败，请检查网络后重试',
                          type: AppToastType.error,
                        );
                      }
                      return false;
                    }
                  },
                  onDismissed: (_) {
                    setState(() {
                      _allRecords.removeWhere(
                        (record) => record['id']?.toString() == id,
                      );
                      _filtered.removeWhere(
                        (record) => record['id']?.toString() == id,
                      );
                      _selectedIdx = null;
                    });
                    ref.invalidate(latestHealthProvider);
                  },
                  child: GestureDetector(
                    onTap: () {
                      final chartIndex = chartRecords.indexWhere(
                        (record) => record['id']?.toString() == id,
                      );
                      if (chartIndex < 0) return;
                      setState(
                        () => _selectedIdx = isSelected ? null : chartIndex,
                      );
                    },
                    child: AnimatedContainer(
                      duration: const Duration(milliseconds: 180),
                      color: isSelected
                          ? _color.withValues(alpha: 0.10)
                          : Colors.white,
                      child: Column(
                        children: [
                          Padding(
                            padding: const EdgeInsets.symmetric(
                              horizontal: 14,
                              vertical: 10,
                            ),
                            child: Row(
                              children: [
                                Container(
                                  width: 36,
                                  height: 36,
                                  decoration: BoxDecoration(
                                    color: _color.withAlpha(20),
                                    borderRadius: AppRadius.smBorder,
                                  ),
                                  child: Center(
                                    child: Icon(
                                      _getMetricIcon(_selected),
                                      size: 19,
                                      color: _color,
                                    ),
                                  ),
                                ),
                                const SizedBox(width: 12),
                                Expanded(
                                  child: Text(
                                    _formatRecordTime(date),
                                    style: const TextStyle(
                                      fontSize: 14,
                                      color: AppColors.textSecondary,
                                      fontWeight: FontWeight.w500,
                                    ),
                                  ),
                                ),
                                Column(
                                  crossAxisAlignment: CrossAxisAlignment.end,
                                  children: [
                                    Text(
                                      '$display $_unit',
                                      style: TextStyle(
                                        fontSize: 19,
                                        fontWeight: FontWeight.w700,
                                        color: abnormal
                                            ? AppColors.errorText
                                            : AppColors.textPrimary,
                                      ),
                                    ),
                                    if (status.isNotEmpty) ...[
                                      const SizedBox(height: 2),
                                      Text(
                                        status,
                                        style: const TextStyle(
                                          fontSize: 12,
                                          color: AppColors.errorText,
                                          fontWeight: FontWeight.w600,
                                        ),
                                      ),
                                    ],
                                  ],
                                ),
                              ],
                            ),
                          ),
                          if (!isLast)
                            const Padding(
                              padding: EdgeInsets.only(left: 62),
                              child: Divider(
                                height: 1,
                                thickness: 0.7,
                                color: Color(0xFFE8ECF2),
                              ),
                            ),
                        ],
                      ),
                    ),
                  ),
                );
              }),
            ],
          ),
        ),
      ],
    );
  }

  IconData _getMetricIcon(String key) {
    return _metrics.firstWhere(
          (metric) => metric['key'] == key,
          orElse: () => _metrics.first,
        )['icon']
        as IconData;
  }
}

class _StatisticItem extends StatelessWidget {
  final String label;
  final String value;
  final String unit;

  const _StatisticItem({
    required this.label,
    required this.value,
    required this.unit,
  });

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(
            label,
            style: const TextStyle(fontSize: 13, color: AppColors.textHint),
          ),
          const SizedBox(height: 4),
          Text(
            value,
            style: const TextStyle(
              fontSize: 18,
              fontWeight: FontWeight.w700,
              color: AppColors.textPrimary,
            ),
          ),
          const SizedBox(height: 2),
          Text(
            unit,
            style: const TextStyle(fontSize: 11, color: AppColors.textHint),
          ),
        ],
      ),
    );
  }
}

class _ChartLegend extends StatelessWidget {
  final Color color;
  final String label;

  const _ChartLegend({required this.color, required this.label});

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          width: 14,
          height: 3,
          decoration: BoxDecoration(
            color: color,
            borderRadius: AppRadius.pillBorder,
          ),
        ),
        const SizedBox(width: 5),
        Text(
          label,
          style: const TextStyle(fontSize: 12, color: AppColors.textSecondary),
        ),
      ],
    );
  }
}
