import 'dart:async';
import 'dart:io' show Platform;

import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:permission_handler/permission_handler.dart';

import '../../core/app_colors.dart';
import '../../core/app_module_visuals.dart';
import '../../core/app_theme.dart';
import '../../core/navigation_provider.dart';
import '../../models/ble_device.dart';
import '../../models/bp_reading.dart';
import '../../providers/auth_provider.dart';
import '../../providers/omron_device_provider.dart';
import '../../services/health_ble_service.dart';
import '../../widgets/ble_sync_dialog.dart';
import '../../widgets/app_toast.dart';

const _deviceVisual = AppModuleVisuals.device;

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

  @override
  ConsumerState<DeviceManagementPage> createState() =>
      _DeviceManagementPageState();
}

class _DeviceManagementPageState extends ConsumerState<DeviceManagementPage>
    with SingleTickerProviderStateMixin {
  static const _freshScanWindow = Duration(seconds: 2);
  static const _sameDeviceRetryWindow = Duration(seconds: 3);

  StreamSubscription<List<ScanResult>>? _scanSub;
  late final HealthBleService _bleService;
  late final AnimationController _scanCtrl;
  late final Animation<double> _scanAnim;
  final _recentAttempts = <String, DateTime>{};
  String? _busyDeviceId;
  String? _connectedDeviceId;
  DateTime? _scanStartedAt;
  String _activeScanBoundKey = '';
  bool _scanning = false;
  bool _permissionBlocked = false;
  bool _disposed = false;

  @override
  void initState() {
    super.initState();
    _bleService = ref.read(healthBleServiceProvider);
    _scanCtrl = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1400),
    )..repeat(reverse: true);
    _scanAnim = Tween(
      begin: 0.85,
      end: 1.35,
    ).animate(CurvedAnimation(parent: _scanCtrl, curve: Curves.easeInOut));
  }

  @override
  void dispose() {
    _disposed = true;
    _scanSub?.cancel();
    _scanCtrl.dispose();
    unawaited(FlutterBluePlus.stopScan());
    unawaited(_bleService.disconnect());
    super.dispose();
  }

  Future<void> _startForegroundScan() async {
    if (!await _ensureBlePermissions()) {
      if (mounted) setState(() => _scanning = false);
      return;
    }
    if (_disposed || !mounted) return;

    if (Platform.isAndroid) {
      final locStatus = await Permission.locationWhenInUse.serviceStatus;
      if (_disposed || !mounted) return;
      if (locStatus != ServiceStatus.enabled && mounted) {
        AppToast.show(
          context,
          '请先打开定位服务，否则可能无法发现蓝牙设备',
          type: AppToastType.warning,
        );
      }
    }

    final adapterState = await FlutterBluePlus.adapterState.first;
    if (_disposed || !mounted) return;
    if (adapterState != BluetoothAdapterState.on) {
      try {
        await FlutterBluePlus.turnOn();
      } catch (_) {}
    }

    try {
      await FlutterBluePlus.stopScan();
    } catch (_) {}
    if (_disposed || !mounted) return;
    final boundIds = ref
        .read(omronDeviceProvider)
        .devices
        .map((device) => device.id)
        .toList();
    if (boundIds.isEmpty) {
      _activeScanBoundKey = '';
      if (mounted) setState(() => _scanning = false);
      return;
    }
    _activeScanBoundKey = _boundIdsKey(boundIds);
    _scanStartedAt = DateTime.now();
    await _scanSub?.cancel();
    _scanSub = FlutterBluePlus.onScanResults.listen(_onScanResults);
    try {
      await FlutterBluePlus.startScan(
        withRemoteIds: boundIds,
        androidScanMode: AndroidScanMode.lowLatency,
        oneByOne: true,
      );
      if (mounted) setState(() => _scanning = true);
    } catch (e) {
      if (mounted) setState(() => _scanning = false);
    }
  }

  Future<bool> _ensureBlePermissions() async {
    final statuses = await [
      Permission.bluetoothScan,
      Permission.bluetoothConnect,
    ].request();
    final granted = statuses.values.every((status) => status.isGranted);
    if (granted) {
      _permissionBlocked = false;
      return true;
    }
    _permissionBlocked = true;
    if (_disposed || !mounted) return false;
    AppToast.show(context, '请开启蓝牙权限后再同步设备', type: AppToastType.warning);
    await showDialog<void>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: const Text('需要蓝牙权限'),
        content: const Text('同步已绑定设备需要蓝牙权限，请在系统设置中开启后重试。'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(ctx),
            child: const Text('稍后再说'),
          ),
          TextButton(
            onPressed: () {
              Navigator.pop(ctx);
              openAppSettings();
            },
            child: const Text('去设置'),
          ),
        ],
      ),
    );
    return false;
  }

  void _onScanResults(List<ScanResult> results) {
    if (!mounted || _busyDeviceId != null) return;
    final scanStartedAt = _scanStartedAt;
    if (scanStartedAt == null) return;
    final boundDevices = ref.read(omronDeviceProvider).devices;
    if (boundDevices.isEmpty) return;

    final candidates = results.where((result) {
      final id = result.device.remoteId.toString();
      if (result.timeStamp.isBefore(scanStartedAt)) return false;
      if (!result.advertisementData.connectable) return false;
      if (DateTime.now().difference(result.timeStamp) > _freshScanWindow) {
        return false;
      }
      final boundDevice = ref.read(omronDeviceProvider).findById(id);
      if (boundDevice == null) return false;
      if (!_isSameBoundDeviceName(result, boundDevice)) return false;
      final scanType = HealthBleService.deviceTypeFromScan(result);
      if (scanType != null && scanType != boundDevice.type) return false;
      final lastAttempt = _recentAttempts[id];
      if (lastAttempt == null) return true;
      return DateTime.now().difference(lastAttempt) > _sameDeviceRetryWindow;
    }).toList()..sort((a, b) => b.rssi.compareTo(a.rssi));

    if (candidates.isEmpty) return;
    final result = candidates.first;
    final bound = ref
        .read(omronDeviceProvider)
        .findById(result.device.remoteId.toString());
    if (bound == null) return;
    unawaited(_syncDevice(result, bound));
  }

  bool _isSameBoundDeviceName(ScanResult result, BoundBleDevice bound) {
    final scannedName = _scanDeviceName(result);
    if (scannedName.isEmpty) return false;
    return _normalizeDeviceName(scannedName) ==
        _normalizeDeviceName(bound.name);
  }

  String _scanDeviceName(ScanResult result) {
    final advName = result.advertisementData.advName.trim();
    if (advName.isNotEmpty) return advName;
    return result.device.platformName.trim();
  }

  String _normalizeDeviceName(String value) {
    return value.trim().toUpperCase();
  }

  String _boundIdsKey(List<String> ids) {
    final sorted = [...ids]..sort();
    return sorted.join('|');
  }

  Future<void> _syncDevice(ScanResult result, BoundBleDevice bound) async {
    if (_disposed || !mounted || _busyDeviceId != null) return;
    _recentAttempts[bound.id] = DateTime.now();
    setState(() {
      _busyDeviceId = bound.id;
      _connectedDeviceId = null;
    });

    await FlutterBluePlus.stopScan();
    if (_disposed || !mounted) return;
    setState(() => _scanning = false);

    try {
      final syncResult = await _bleService.syncBoundDevice(
        result.device,
        bound,
        timeout: const Duration(seconds: 35),
        onConnected: () {
          if (!_disposed && mounted) {
            setState(() => _connectedDeviceId = bound.id);
          }
        },
        onMeasurementReceived: () {
          // Measurement has arrived; parsing and persistence happen below.
        },
      );
      if (syncResult is BloodPressureSyncResult) {
        if (_disposed || !mounted) return;
        final saved = await _persistBloodPressure(
          syncResult.device,
          syncResult.reading,
        );
        if (!_disposed && mounted && saved) {
          await _showBloodPressureDialog(syncResult.reading);
        }
      }
    } on TimeoutException {
      if (!_disposed && mounted && _connectedDeviceId == bound.id) {
        AppToast.show(context, '已连接设备，但本次未收到测量数据', type: AppToastType.warning);
      }
    } on Exception {
      if (!_disposed && mounted) {
        AppToast.show(context, '数据录入失败，请稍后重试', type: AppToastType.error);
      }
    } finally {
      await _bleService.disconnect();
      if (!_disposed && mounted) {
        setState(() {
          _busyDeviceId = null;
          _connectedDeviceId = null;
        });
      }
      if (!_disposed && mounted) unawaited(_startForegroundScan());
    }
  }

  Future<bool> _persistBloodPressure(
    BoundBleDevice device,
    BpReading reading,
  ) async {
    final notifier = ref.read(omronDeviceProvider.notifier);
    if (await notifier.isDuplicateReading(device, reading)) return false;

    final api = ref.read(apiClientProvider);
    await api.post('/api/health-records', data: reading.toHealthRecord());
    final heartRateRecord = reading.toHeartRateRecord();
    if (heartRateRecord != null) {
      await api.post('/api/health-records', data: heartRateRecord);
    }
    await notifier.recordSuccessfulSync(device: device, reading: reading);
    return true;
  }

  Future<void> _showBloodPressureDialog(BpReading reading) {
    return showBleSyncDialog(context, reading: reading);
  }

  @override
  Widget build(BuildContext context) {
    final state = ref.watch(omronDeviceProvider);
    final devices = state.devices;
    final connected = _connectedDeviceId != null;
    final boundKey = _boundIdsKey(devices.map((device) => device.id).toList());

    if (devices.isNotEmpty &&
        !_scanning &&
        _busyDeviceId == null &&
        !_permissionBlocked &&
        _activeScanBoundKey != boundKey) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (!_disposed && mounted) unawaited(_startForegroundScan());
      });
    }

    ref.listen<DeviceBindState>(omronDeviceProvider, (prev, next) {
      final nextIds = next.devices.map((device) => device.id).toList();
      final nextKey = _boundIdsKey(nextIds);
      if (nextIds.isEmpty) {
        _activeScanBoundKey = '';
        unawaited(FlutterBluePlus.stopScan());
        if (!_disposed && mounted) setState(() => _scanning = false);
        return;
      }
      if (nextKey != _activeScanBoundKey && _busyDeviceId == null) {
        if (_permissionBlocked) return;
        WidgetsBinding.instance.addPostFrameCallback((_) {
          if (!_disposed && mounted) unawaited(_startForegroundScan());
        });
      }
    });

    return GradientScaffold(
      appBar: AppBar(
        title: const Text('蓝牙设备'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => popRoute(ref),
        ),
        actions: [
          Padding(
            padding: const EdgeInsets.only(right: 10),
            child: IconButton(
              tooltip: '新增设备',
              onPressed: () => pushRoute(ref, 'deviceScan'),
              style: IconButton.styleFrom(
                backgroundColor: _deviceVisual.lightColor,
                foregroundColor: _deviceVisual.color,
                fixedSize: const Size(40, 40),
              ),
              icon: const Icon(Icons.add_rounded),
            ),
          ),
        ],
      ),
      body: Stack(
        children: [
          ListView(
            padding: const EdgeInsets.fromLTRB(18, 10, 18, 120),
            children: [
              _DevicesHeader(deviceCount: devices.length),
              const SizedBox(height: 18),
              if (devices.isEmpty)
                const _EmptyDevices()
              else
                for (final type in BleDeviceType.values)
                  if (state.devicesOfType(type).isNotEmpty) ...[
                    _DeviceSection(
                      type: type,
                      devices: state.devicesOfType(type),
                      connectedDeviceId: _connectedDeviceId,
                      busyDeviceId: _busyDeviceId,
                      onUnbind: _confirmUnbind,
                    ),
                    const SizedBox(height: 18),
                  ],
            ],
          ),
          if (devices.isNotEmpty)
            Positioned(
              right: 18,
              bottom: 20,
              child: _ScanIndicator(
                animation: _scanAnim,
                scanning: _scanning,
                syncing: connected,
              ),
            ),
        ],
      ),
    );
  }

  Future<void> _confirmUnbind(BoundBleDevice device) async {
    final ok = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
        title: const Text('解绑设备'),
        content: Text('确定解绑这台${device.type.label}吗？'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(ctx, false),
            child: const Text('取消'),
          ),
          TextButton(
            onPressed: () => Navigator.pop(ctx, true),
            style: TextButton.styleFrom(foregroundColor: AppColors.error),
            child: const Text('解绑'),
          ),
        ],
      ),
    );
    if (ok == true) {
      await ref.read(omronDeviceProvider.notifier).unbind(device.id);
    }
  }
}

class _DevicesHeader extends StatelessWidget {
  final int deviceCount;

  const _DevicesHeader({required this.deviceCount});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.fromLTRB(18, 18, 18, 18),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(20),
        border: Border.all(color: AppColors.borderLight, width: 1.1),
        boxShadow: [AppTheme.shadowLight],
      ),
      child: Row(
        children: [
          Container(
            width: 50,
            height: 50,
            decoration: BoxDecoration(
              gradient: _deviceVisual.gradient,
              borderRadius: BorderRadius.circular(16),
            ),
            child: const Icon(
              Icons.bluetooth_audio_rounded,
              color: Colors.white,
              size: 27,
            ),
          ),
          const SizedBox(width: 14),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text(
                  '已绑定设备',
                  style: TextStyle(
                    fontSize: 19,
                    fontWeight: FontWeight.w900,
                    color: AppColors.textPrimary,
                  ),
                ),
                const SizedBox(height: 4),
                Text(
                  '$deviceCount 台设备',
                  style: const TextStyle(
                    fontSize: 13,
                    fontWeight: FontWeight.w800,
                    color: AppColors.textSecondary,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _DeviceSection extends StatelessWidget {
  final BleDeviceType type;
  final List<BoundBleDevice> devices;
  final String? connectedDeviceId;
  final String? busyDeviceId;
  final ValueChanged<BoundBleDevice> onUnbind;

  const _DeviceSection({
    required this.type,
    required this.devices,
    required this.connectedDeviceId,
    required this.busyDeviceId,
    required this.onUnbind,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.only(bottom: 10),
          child: Row(
            children: [
              Container(
                width: 34,
                height: 34,
                decoration: BoxDecoration(
                  color: _deviceVisual.lightColor,
                  borderRadius: BorderRadius.circular(11),
                  border: Border.all(color: AppColors.borderLight),
                ),
                child: Icon(type.icon, size: 19, color: _deviceVisual.color),
              ),
              const SizedBox(width: 10),
              Text(
                type.label,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w900,
                  color: AppColors.textPrimary,
                ),
              ),
              const SizedBox(width: 8),
              Text(
                '${devices.length}',
                style: const TextStyle(
                  fontSize: 12,
                  fontWeight: FontWeight.w800,
                  color: AppColors.textHint,
                ),
              ),
            ],
          ),
        ),
        for (final device in devices)
          Padding(
            padding: const EdgeInsets.only(bottom: 10),
            child: _BoundDeviceTile(
              device: device,
              connected: connectedDeviceId == device.id,
              onUnbind: () => onUnbind(device),
            ),
          ),
      ],
    );
  }
}

class _BoundDeviceTile extends StatelessWidget {
  final BoundBleDevice device;
  final bool connected;
  final VoidCallback onUnbind;

  const _BoundDeviceTile({
    required this.device,
    required this.connected,
    required this.onUnbind,
  });

  @override
  Widget build(BuildContext context) {
    final accent = connected ? AppColors.success : AppColors.textHint;
    return AnimatedContainer(
      duration: const Duration(milliseconds: 180),
      padding: const EdgeInsets.fromLTRB(16, 15, 10, 15),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(18),
        border: Border.all(
          color: connected ? AppColors.success : AppColors.border,
          width: connected ? 1.4 : 1.1,
        ),
        boxShadow: connected
            ? [
                BoxShadow(
                  color: AppColors.success.withValues(alpha: 0.14),
                  blurRadius: 18,
                  offset: const Offset(0, 8),
                ),
              ]
            : AppColors.cardShadowLight,
      ),
      child: Row(
        children: [
          AnimatedContainer(
            duration: const Duration(milliseconds: 180),
            width: 50,
            height: 50,
            decoration: BoxDecoration(
              color: connected
                  ? AppColors.successLight
                  : const Color(0xFFF8FAFC),
              borderRadius: BorderRadius.circular(16),
              border: Border.all(color: AppColors.borderLight),
            ),
            child: Icon(device.type.icon, color: accent, size: 25),
          ),
          const SizedBox(width: 14),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  device.name,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: const TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.w800,
                    color: AppColors.textPrimary,
                  ),
                ),
                const SizedBox(height: 4),
                Text(
                  '最近同步：${_formatLastSync(device.lastSyncAt)}',
                  style: const TextStyle(
                    fontSize: 13,
                    fontWeight: FontWeight.w700,
                    color: AppColors.textHint,
                  ),
                ),
              ],
            ),
          ),
          if (connected)
            Container(
              margin: const EdgeInsets.only(right: 4),
              padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
              decoration: BoxDecoration(
                color: AppColors.successLight,
                borderRadius: BorderRadius.circular(999),
              ),
              child: const Text(
                '已连接',
                style: TextStyle(
                  fontSize: 12,
                  height: 1,
                  fontWeight: FontWeight.w900,
                  color: AppColors.success,
                ),
              ),
            ),
          IconButton(
            tooltip: '解绑设备',
            onPressed: connected ? null : onUnbind,
            icon: const Icon(Icons.delete_outline_rounded),
            color: connected ? AppColors.textHint : AppColors.error,
          ),
        ],
      ),
    );
  }

  String _formatLastSync(DateTime? value) {
    if (value == null) return '暂无';
    final now = DateTime.now();
    final dayLabel =
        value.year == now.year &&
            value.month == now.month &&
            value.day == now.day
        ? '今天'
        : '${value.month}/${value.day}';
    final minute = value.minute.toString().padLeft(2, '0');
    return '$dayLabel ${value.hour}:$minute';
  }
}

class _EmptyDevices extends StatelessWidget {
  const _EmptyDevices();

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.fromLTRB(24, 46, 24, 46),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(22),
        border: Border.all(color: AppColors.borderLight, width: 1.1),
        boxShadow: [AppTheme.shadowLight],
      ),
      child: Column(
        children: [
          Container(
            width: 72,
            height: 72,
            decoration: BoxDecoration(
              color: const Color(0xFFEFF6FF),
              borderRadius: BorderRadius.circular(22),
            ),
            child: const Icon(
              Icons.bluetooth_disabled_rounded,
              color: Color(0xFF2563EB),
              size: 36,
            ),
          ),
          const SizedBox(height: 18),
          const Text(
            '还没有绑定设备',
            style: TextStyle(
              fontSize: 19,
              fontWeight: FontWeight.w900,
              color: AppColors.textPrimary,
            ),
          ),
          const SizedBox(height: 8),
          const Text(
            '右上角添加设备',
            textAlign: TextAlign.center,
            style: TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w700,
              color: AppColors.textSecondary,
            ),
          ),
        ],
      ),
    );
  }
}

class _ScanIndicator extends StatelessWidget {
  final Animation<double> animation;
  final bool scanning;
  final bool syncing;

  const _ScanIndicator({
    required this.animation,
    required this.scanning,
    required this.syncing,
  });

  @override
  Widget build(BuildContext context) {
    final active = scanning || syncing;
    return SizedBox(
      width: 88,
      height: 88,
      child: Stack(
        alignment: Alignment.center,
        children: [
          if (active) ...[
            AnimatedBuilder(
              animation: animation,
              builder: (context, child) => Container(
                width: 78 * animation.value,
                height: 78 * animation.value,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: const Color(0xFF2563EB).withValues(alpha: 0.10),
                ),
              ),
            ),
            AnimatedBuilder(
              animation: animation,
              builder: (context, child) => Container(
                width: 64 * animation.value,
                height: 64 * animation.value,
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: const Color(0xFF2563EB).withValues(alpha: 0.18),
                ),
              ),
            ),
          ],
          Container(
            width: 58,
            height: 58,
            decoration: BoxDecoration(
              color: const Color(0xFF2563EB),
              shape: BoxShape.circle,
              boxShadow: [
                BoxShadow(
                  color: const Color(0xFF2563EB).withValues(alpha: 0.24),
                  blurRadius: 18,
                  offset: const Offset(0, 8),
                ),
              ],
            ),
            child: Icon(
              syncing
                  ? Icons.bluetooth_connected_rounded
                  : Icons.bluetooth_searching_rounded,
              color: Colors.white,
              size: 28,
            ),
          ),
        ],
      ),
    );
  }
}
