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

import '../../core/api_client.dart';
import '../../core/app_colors.dart';
import '../../core/app_design_tokens.dart';
import '../../core/app_module_visuals.dart';
import '../../core/app_theme.dart';
import '../../core/navigation_provider.dart';
import '../../providers/auth_provider.dart';
import '../../widgets/app_error_state.dart';
import '../../widgets/app_toast.dart';
import 'notification_prefs_logic.dart';

final notificationPrefsProvider =
    NotifierProvider<NotificationPrefsNotifier, NotificationPrefsViewState>(
      NotificationPrefsNotifier.new,
    );

class NotificationPrefsNotifier extends Notifier<NotificationPrefsViewState> {
  @override
  NotificationPrefsViewState build() {
    Future.microtask(load);
    return const NotificationPrefsViewState(loading: true);
  }

  Future<void> load() async {
    state = state.copyWith(loading: true, clearLoadError: true);
    try {
      final response = await ref
          .read(apiClientProvider)
          .get('/api/notification-prefs');
      final data = response.data['data'];
      if (data is! Map) throw const ApiException('服务器返回的通知设置无效');
      state = NotificationPrefsViewState(
        prefs: NotificationPrefs.fromJson(data),
      );
    } catch (error) {
      state = NotificationPrefsViewState(loadError: _message(error));
    }
  }

  Future<String?> updateBool({
    required String operationKey,
    required String backendField,
    required bool value,
  }) => _save(operationKey, {backendField: value});

  Future<String?> setDndStart(TimeOfDay time) =>
      _save('dndStart', {'dndStartMinutes': time.hour * 60 + time.minute});

  Future<String?> setDndEnd(TimeOfDay time) =>
      _save('dndEnd', {'dndEndMinutes': time.hour * 60 + time.minute});

  Future<String?> saveHealthMetrics(Set<HealthReminderMetric> metrics) {
    if (metrics.isEmpty) return Future.value('至少选择一项提醒指标');
    return _save('healthMetrics', healthMetricUpdatePayload(metrics));
  }

  Future<String?> _save(
    String operationKey,
    Map<String, dynamic> payload,
  ) async {
    if (state.prefs == null || state.savingKeys.contains(operationKey)) {
      return null;
    }
    final saving = {...state.savingKeys, operationKey};
    state = state.copyWith(savingKeys: saving);
    try {
      final response = await ref
          .read(apiClientProvider)
          .put('/api/notification-prefs', data: payload);
      final data = response.data['data'];
      if (data is! Map) throw const ApiException('服务器未返回最新通知设置');
      state = NotificationPrefsViewState(
        prefs: NotificationPrefs.fromJson(data),
        savingKeys: {...saving}..remove(operationKey),
      );
      return null;
    } catch (error) {
      state = state.copyWith(savingKeys: {...saving}..remove(operationKey));
      return _message(error);
    }
  }

  String _message(Object error) =>
      error is ApiException ? error.message : '保存失败，请检查网络后重试';
}

class NotificationPrefsPage extends ConsumerWidget {
  const NotificationPrefsPage({super.key});

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

    return GradientScaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        elevation: 0,
        leading: IconButton(
          icon: const Icon(
            Icons.arrow_back_ios_new,
            color: AppColors.textPrimary,
          ),
          onPressed: () => popRoute(ref),
        ),
        title: const Text(
          '消息通知',
          style: TextStyle(
            fontSize: 21,
            fontWeight: FontWeight.w600,
            color: AppColors.textPrimary,
          ),
        ),
        centerTitle: true,
      ),
      body: viewState.loading
          ? const Center(child: CircularProgressIndicator(strokeWidth: 2))
          : viewState.loadError != null
          ? AppErrorState(
              title: '通知设置加载失败',
              subtitle: viewState.loadError!,
              onRetry: () =>
                  ref.read(notificationPrefsProvider.notifier).load(),
            )
          : _PreferencesContent(
              prefs: viewState.prefs!,
              savingKeys: viewState.savingKeys,
            ),
    );
  }
}

class _PreferencesContent extends ConsumerWidget {
  final NotificationPrefs prefs;
  final Set<String> savingKeys;

  const _PreferencesContent({required this.prefs, required this.savingKeys});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final notifier = ref.read(notificationPrefsProvider.notifier);
    String formatMinutes(int value) =>
        '${(value ~/ 60).toString().padLeft(2, '0')}:${(value % 60).toString().padLeft(2, '0')}';

    Future<void> save(Future<String?> operation) async {
      final error = await operation;
      if (error != null && context.mounted) {
        AppToast.show(context, error, type: AppToastType.error);
      }
    }

    return SingleChildScrollView(
      padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _SettingsListSection(
            title: '推送通知',
            children: [
              _SwitchTile(
                title: '允许推送通知',
                subtitle: '关闭后将不再收到任何系统通知',
                value: prefs.pushEnabled,
                saving: savingKeys.contains('pushEnabled'),
                showDivider: false,
                onChanged: savingKeys.contains('pushEnabled')
                    ? null
                    : (value) => save(
                        notifier.updateBool(
                          operationKey: 'pushEnabled',
                          backendField: 'pushEnabled',
                          value: value,
                        ),
                      ),
              ),
            ],
          ),
          const SizedBox(height: 24),
          _SettingsListSection(
            title: '通知类型',
            children: [
              _SwitchTile(
                icon: AppModuleVisuals.medication.icon,
                iconBg: AppModuleVisuals.medication.lightColor,
                iconColor: AppModuleVisuals.medication.color,
                title: '用药提醒',
                subtitle: '服药时间到达时提醒您',
                value: prefs.medicationReminder,
                saving: savingKeys.contains('medication'),
                onChanged: savingKeys.contains('medication')
                    ? null
                    : (value) => save(
                        notifier.updateBool(
                          operationKey: 'medication',
                          backendField: 'medicationReminder',
                          value: value,
                        ),
                      ),
              ),
              _SwitchTile(
                icon: LucideIcons.triangleAlert,
                iconBg: AppModuleVisuals.health.lightColor,
                iconColor: AppModuleVisuals.health.color,
                title: '健康异常提醒',
                subtitle: '检测到数据异常时及时通知',
                value: prefs.abnormalAlert,
                saving: savingKeys.contains('healthAlert'),
                onChanged: savingKeys.contains('healthAlert')
                    ? null
                    : (value) => save(
                        notifier.updateBool(
                          operationKey: 'healthAlert',
                          backendField: 'abnormalAlert',
                          value: value,
                        ),
                      ),
              ),
              _SwitchTile(
                icon: AppModuleVisuals.followup.icon,
                iconBg: AppModuleVisuals.followup.lightColor,
                iconColor: AppModuleVisuals.followup.color,
                title: '复查日期提醒',
                subtitle: '复查日前提醒您安排就医',
                value: prefs.followUpReminder,
                saving: savingKeys.contains('followUp'),
                onChanged: savingKeys.contains('followUp')
                    ? null
                    : (value) => save(
                        notifier.updateBool(
                          operationKey: 'followUp',
                          backendField: 'followUpReminder',
                          value: value,
                        ),
                      ),
              ),
              _SwitchTile(
                icon: AppModuleVisuals.ai.icon,
                iconBg: AppModuleVisuals.ai.lightColor,
                iconColor: AppModuleVisuals.ai.color,
                title: 'AI 回复通知',
                subtitle: 'AI 助手回复时发送通知',
                value: prefs.doctorReply,
                saving: savingKeys.contains('aiReply'),
                showDivider: false,
                onChanged: savingKeys.contains('aiReply')
                    ? null
                    : (value) => save(
                        notifier.updateBool(
                          operationKey: 'aiReply',
                          backendField: 'doctorReply',
                          value: value,
                        ),
                      ),
              ),
            ],
          ),
          const SizedBox(height: 24),
          _SettingsListSection(
            title: '健康录入提醒',
            children: [
              _SwitchTile(
                icon: LucideIcons.alarmClock,
                iconBg: AppModuleVisuals.health.lightColor,
                iconColor: AppModuleVisuals.health.color,
                title: '每日录入提醒',
                subtitle: '仅提醒当天尚未录入的健康指标',
                value: prefs.healthRecordReminder,
                saving: savingKeys.contains('healthRecord'),
                onChanged: savingKeys.contains('healthRecord')
                    ? null
                    : (value) => save(
                        notifier.updateBool(
                          operationKey: 'healthRecord',
                          backendField: 'healthRecordReminder',
                          value: value,
                        ),
                      ),
              ),
              _ActionTile(
                icon: LucideIcons.slidersHorizontal,
                title: '提醒指标',
                subtitle: healthMetricSummary(prefs.enabledHealthMetrics),
                enabled:
                    prefs.healthRecordReminder &&
                    !savingKeys.contains('healthMetrics'),
                saving: savingKeys.contains('healthMetrics'),
                onTap: () => _showHealthMetricSheet(
                  context,
                  prefs.enabledHealthMetrics,
                  notifier.saveHealthMetrics,
                ),
              ),
            ],
          ),
          const SizedBox(height: 24),
          _SettingsListSection(
            title: '免打扰时段',
            children: [
              _SwitchTile(
                title: '开启免打扰模式',
                subtitle: prefs.dndEnabled
                    ? '${formatMinutes(prefs.dndStartMinutes)} - ${formatMinutes(prefs.dndEndMinutes)} 期间静音'
                    : '关闭后全天接收通知',
                value: prefs.dndEnabled,
                saving: savingKeys.contains('dndEnabled'),
                showDivider: prefs.dndEnabled,
                onChanged: savingKeys.contains('dndEnabled')
                    ? null
                    : (value) => save(
                        notifier.updateBool(
                          operationKey: 'dndEnabled',
                          backendField: 'dndEnabled',
                          value: value,
                        ),
                      ),
              ),
              if (prefs.dndEnabled)
                Container(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 16,
                    vertical: 14,
                  ),
                  color: AppTheme.surface,
                  child: Row(
                    children: [
                      Expanded(
                        child: _TimeButton(
                          label: '开始',
                          time: formatMinutes(prefs.dndStartMinutes),
                          saving: savingKeys.contains('dndStart'),
                          onTap: () async {
                            final picked = await showAppTimePicker(
                              context,
                              initialTime: TimeOfDay(
                                hour: prefs.dndStartMinutes ~/ 60,
                                minute: prefs.dndStartMinutes % 60,
                              ),
                            );
                            if (picked != null && context.mounted) {
                              await save(notifier.setDndStart(picked));
                            }
                          },
                        ),
                      ),
                      const Padding(
                        padding: EdgeInsets.symmetric(horizontal: 12),
                        child: Text(
                          '~',
                          style: TextStyle(
                            fontSize: 19,
                            color: AppColors.textHint,
                          ),
                        ),
                      ),
                      Expanded(
                        child: _TimeButton(
                          label: '结束',
                          time: formatMinutes(prefs.dndEndMinutes),
                          saving: savingKeys.contains('dndEnd'),
                          onTap: () async {
                            final picked = await showAppTimePicker(
                              context,
                              initialTime: TimeOfDay(
                                hour: prefs.dndEndMinutes ~/ 60,
                                minute: prefs.dndEndMinutes % 60,
                              ),
                            );
                            if (picked != null && context.mounted) {
                              await save(notifier.setDndEnd(picked));
                            }
                          },
                        ),
                      ),
                    ],
                  ),
                ),
            ],
          ),
          const SizedBox(height: 40),
        ],
      ),
    );
  }
}

Future<void> _showHealthMetricSheet(
  BuildContext context,
  Set<HealthReminderMetric> selected,
  Future<String?> Function(Set<HealthReminderMetric>) onSave,
) => showModalBottomSheet<void>(
  context: context,
  useSafeArea: true,
  isScrollControlled: true,
  backgroundColor: Colors.transparent,
  builder: (context) => _HealthMetricSheet(selected: selected, onSave: onSave),
);

class _HealthMetricSheet extends StatefulWidget {
  final Set<HealthReminderMetric> selected;
  final Future<String?> Function(Set<HealthReminderMetric>) onSave;

  const _HealthMetricSheet({required this.selected, required this.onSave});

  @override
  State<_HealthMetricSheet> createState() => _HealthMetricSheetState();
}

class _HealthMetricSheetState extends State<_HealthMetricSheet> {
  late final Set<HealthReminderMetric> _draft = {...widget.selected};
  bool _saving = false;
  String? _error;

  Future<void> _save() async {
    if (_draft.isEmpty) {
      setState(() => _error = '至少选择一项提醒指标');
      return;
    }
    setState(() {
      _saving = true;
      _error = null;
    });
    final error = await widget.onSave(_draft);
    if (!mounted) return;
    if (error == null) {
      Navigator.pop(context);
      return;
    }
    setState(() {
      _saving = false;
      _error = error;
    });
  }

  @override
  Widget build(BuildContext context) => Container(
    padding: EdgeInsets.fromLTRB(
      20,
      12,
      20,
      18 + MediaQuery.viewInsetsOf(context).bottom,
    ),
    decoration: const BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
    ),
    child: Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Center(
          child: Container(
            width: 38,
            height: 4,
            decoration: BoxDecoration(
              color: AppColors.border,
              borderRadius: AppRadius.pillBorder,
            ),
          ),
        ),
        const SizedBox(height: 18),
        const Text(
          '选择提醒指标',
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.w600,
            color: AppColors.textPrimary,
          ),
        ),
        const SizedBox(height: 5),
        const Text(
          '当天未录入已选指标时，小脉会发送提醒。',
          style: TextStyle(fontSize: 13, color: AppColors.textSecondary),
        ),
        const SizedBox(height: 14),
        for (final metric in HealthReminderMetric.values)
          _MetricCheckbox(
            metric: metric,
            selected: _draft.contains(metric),
            enabled: !_saving,
            onChanged: (selected) {
              setState(() {
                selected ? _draft.add(metric) : _draft.remove(metric);
                _error = null;
              });
            },
          ),
        if (_error != null) ...[
          const SizedBox(height: 8),
          Text(
            _error!,
            style: const TextStyle(
              fontSize: 13,
              fontWeight: FontWeight.w700,
              color: AppColors.error,
            ),
          ),
        ],
        const SizedBox(height: 18),
        SizedBox(
          width: double.infinity,
          child: FilledButton(
            onPressed: _saving ? null : _save,
            child: Text(_saving ? '保存中...' : '保存'),
          ),
        ),
      ],
    ),
  );
}

class _MetricCheckbox extends StatelessWidget {
  final HealthReminderMetric metric;
  final bool selected;
  final bool enabled;
  final ValueChanged<bool> onChanged;

  const _MetricCheckbox({
    required this.metric,
    required this.selected,
    required this.enabled,
    required this.onChanged,
  });

  @override
  Widget build(BuildContext context) => InkWell(
    onTap: enabled ? () => onChanged(!selected) : null,
    borderRadius: AppRadius.mdBorder,
    child: Padding(
      padding: const EdgeInsets.symmetric(vertical: 7),
      child: Row(
        children: [
          Checkbox(
            value: selected,
            onChanged: enabled ? (value) => onChanged(value ?? false) : null,
          ),
          const SizedBox(width: 8),
          Text(
            metric.label,
            style: const TextStyle(
              fontSize: 16,
              fontWeight: FontWeight.w700,
              color: AppColors.textPrimary,
            ),
          ),
        ],
      ),
    ),
  );
}

class _SectionTitle extends StatelessWidget {
  final String title;
  const _SectionTitle({required this.title});

  @override
  Widget build(BuildContext context) => Padding(
    padding: const EdgeInsets.only(left: 4, bottom: 10),
    child: Text(
      title,
      style: const TextStyle(
        fontSize: 17,
        fontWeight: FontWeight.w600,
        color: AppColors.textSecondary,
      ),
    ),
  );
}

class _SettingsListSection extends StatelessWidget {
  final String title;
  final List<Widget> children;

  const _SettingsListSection({required this.title, required this.children});

  @override
  Widget build(BuildContext context) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      _SectionTitle(title: title),
      ClipRRect(
        borderRadius: AppRadius.mdBorder,
        child: ColoredBox(
          color: AppTheme.surface,
          child: Column(children: children),
        ),
      ),
    ],
  );
}

class _SwitchTile extends StatelessWidget {
  final IconData? icon;
  final Color? iconBg;
  final Color? iconColor;
  final String title;
  final String? subtitle;
  final bool value;
  final bool saving;
  final bool showDivider;
  final ValueChanged<bool>? onChanged;

  const _SwitchTile({
    this.icon,
    this.iconBg,
    this.iconColor,
    required this.title,
    this.subtitle,
    required this.value,
    this.saving = false,
    this.showDivider = true,
    required this.onChanged,
  });

  @override
  Widget build(BuildContext context) => _SettingsRow(
    icon: icon,
    iconBg: iconBg,
    iconColor: iconColor,
    title: title,
    subtitle: subtitle,
    showDivider: showDivider,
    trailing: saving
        ? const SizedBox(
            width: 22,
            height: 22,
            child: CircularProgressIndicator(strokeWidth: 2),
          )
        : _AppSwitch(value: value, onChanged: onChanged),
  );
}

class _ActionTile extends StatelessWidget {
  final IconData icon;
  final String title;
  final String subtitle;
  final bool enabled;
  final bool saving;
  final VoidCallback onTap;

  const _ActionTile({
    required this.icon,
    required this.title,
    required this.subtitle,
    required this.enabled,
    required this.saving,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) => Material(
    color: Colors.transparent,
    child: InkWell(
      onTap: enabled ? onTap : null,
      child: _SettingsRow(
        icon: icon,
        iconBg: AppColors.iconBg,
        iconColor: AppColors.primary,
        title: title,
        subtitle: subtitle,
        showDivider: false,
        muted: !enabled,
        trailing: saving
            ? const SizedBox(
                width: 22,
                height: 22,
                child: CircularProgressIndicator(strokeWidth: 2),
              )
            : const Icon(
                Icons.chevron_right_rounded,
                color: AppColors.textHint,
              ),
      ),
    ),
  );
}

class _SettingsRow extends StatelessWidget {
  final IconData? icon;
  final Color? iconBg;
  final Color? iconColor;
  final String title;
  final String? subtitle;
  final Widget trailing;
  final bool showDivider;
  final bool muted;

  const _SettingsRow({
    this.icon,
    this.iconBg,
    this.iconColor,
    required this.title,
    this.subtitle,
    required this.trailing,
    required this.showDivider,
    this.muted = false,
  });

  @override
  Widget build(BuildContext context) => Opacity(
    opacity: muted ? 0.48 : 1,
    child: Column(
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
          child: Row(
            children: [
              if (icon != null) ...[
                Container(
                  width: 34,
                  height: 34,
                  decoration: BoxDecoration(
                    color: iconBg ?? AppColors.iconBg,
                    borderRadius: AppRadius.smBorder,
                  ),
                  child: Icon(
                    icon,
                    size: 20,
                    color: iconColor ?? AppColors.primary,
                  ),
                ),
                const SizedBox(width: 12),
              ],
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: const TextStyle(
                        fontSize: 16,
                        color: AppColors.textPrimary,
                        fontWeight: FontWeight.w700,
                      ),
                    ),
                    if (subtitle?.isNotEmpty == true) ...[
                      const SizedBox(height: 2),
                      Text(
                        subtitle!,
                        style: const TextStyle(
                          fontSize: 13,
                          color: AppColors.textSecondary,
                        ),
                      ),
                    ],
                  ],
                ),
              ),
              const SizedBox(width: 10),
              trailing,
            ],
          ),
        ),
        if (showDivider)
          Padding(
            padding: EdgeInsets.only(left: icon != null ? 60 : 14),
            child: const Divider(
              height: 1,
              thickness: 0.7,
              color: Color(0xFFE8ECF2),
            ),
          ),
      ],
    ),
  );
}

class _AppSwitch extends StatelessWidget {
  final bool value;
  final ValueChanged<bool>? onChanged;

  const _AppSwitch({required this.value, required this.onChanged});

  @override
  Widget build(BuildContext context) => Semantics(
    button: true,
    toggled: value,
    enabled: onChanged != null,
    child: GestureDetector(
      behavior: HitTestBehavior.opaque,
      onTap: onChanged == null ? null : () => onChanged!(!value),
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 160),
        curve: Curves.easeOutCubic,
        width: 46,
        height: 28,
        padding: const EdgeInsets.all(3),
        decoration: BoxDecoration(
          color: value ? AppColors.primary : Colors.white,
          borderRadius: AppRadius.pillBorder,
          border: Border.all(
            color: value
                ? AppColors.primary.withValues(alpha: 0.38)
                : AppColors.border,
          ),
        ),
        child: AnimatedAlign(
          duration: const Duration(milliseconds: 160),
          curve: Curves.easeOutCubic,
          alignment: value ? Alignment.centerRight : Alignment.centerLeft,
          child: Container(
            width: 20,
            height: 20,
            decoration: BoxDecoration(
              color: value ? Colors.white : AppColors.textHint,
              shape: BoxShape.circle,
            ),
          ),
        ),
      ),
    ),
  );
}

class _TimeButton extends StatelessWidget {
  final String label;
  final String time;
  final bool saving;
  final VoidCallback onTap;

  const _TimeButton({
    required this.label,
    required this.time,
    required this.saving,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) => InkWell(
    onTap: saving ? null : onTap,
    borderRadius: AppRadius.mdBorder,
    child: Container(
      padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
      decoration: BoxDecoration(
        border: Border.all(color: AppColors.border),
        borderRadius: AppRadius.mdBorder,
      ),
      child: Column(
        children: [
          Text(
            label,
            style: const TextStyle(fontSize: 14, color: AppColors.textHint),
          ),
          if (saving)
            const SizedBox(
              width: 20,
              height: 20,
              child: CircularProgressIndicator(strokeWidth: 2),
            )
          else
            Text(
              time,
              style: const TextStyle(
                fontSize: 19,
                fontWeight: FontWeight.w600,
                color: AppTheme.primary,
              ),
            ),
        ],
      ),
    ),
  );
}
