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_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/app_toast.dart';
import '../../widgets/ble_sync_dialog.dart';

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

  @override
  ConsumerState<DeviceScanPage> createState() => _DeviceScanPageState();
}

class _DeviceScanPageState extends ConsumerState<DeviceScanPage>
    with SingleTickerProviderStateMixin {
  static const _visibleDeviceWindow = Duration(seconds: 12);

  final _results = <ScanResult>[];
  StreamSubscription<List<ScanResult>>? _scanSub;
  Timer? _scanStopTimer;
  Timer? _resultPruneTimer;
  String? _connectingId;
  DateTime? _scanStartedAt;
  bool _scanning = false;

  late final AnimationController _pulseCtrl;
  late final Animation<double> _pulseAnim;

  @override
  void initState() {
    super.initState();
    _pulseCtrl = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1200),
    )..repeat(reverse: true);
    _pulseAnim = Tween(
      begin: 0.82,
      end: 1.36,
    ).animate(CurvedAnimation(parent: _pulseCtrl, curve: Curves.easeInOut));

    unawaited(_startScan());
  }

  @override
  void dispose() {
    _pulseCtrl.dispose();
    _scanStopTimer?.cancel();
    _resultPruneTimer?.cancel();
    _scanSub?.cancel();
    unawaited(FlutterBluePlus.stopScan());
    unawaited(ref.read(healthBleServiceProvider).disconnect());
    super.dispose();
  }

  Future<void> _startScan() async {
    setState(() {
      _scanning = true;
      _connectingId = null;
      _results.clear();
    });

    if (!await _ensureBlePermissions()) {
      if (mounted) setState(() => _scanning = false);
      return;
    }

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

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

    try {
      await FlutterBluePlus.stopScan();
    } catch (_) {}
    _scanStartedAt = DateTime.now();
    await _scanSub?.cancel();
    _scanSub = FlutterBluePlus.onScanResults.listen(_onScanResults);
    await FlutterBluePlus.startScan(
      timeout: const Duration(seconds: 30),
      androidScanMode: AndroidScanMode.lowLatency,
      oneByOne: true,
    );

    _scanStopTimer?.cancel();
    _scanStopTimer = Timer(const Duration(seconds: 30), () {
      if (mounted) setState(() => _scanning = false);
    });
    _resultPruneTimer?.cancel();
    _resultPruneTimer = Timer.periodic(const Duration(seconds: 1), (_) {
      if (!mounted || _connectingId != null) return;
      final pruned = _visibleResults(_results);
      if (_sameResults(_results, pruned)) return;
      setState(() {
        _results
          ..clear()
          ..addAll(pruned);
      });
    });
  }

  void _onScanResults(List<ScanResult> list) {
    if (!mounted || _connectingId != null) return;
    final scanStartedAt = _scanStartedAt;
    if (scanStartedAt == null) return;
    final boundDevices = ref.read(omronDeviceProvider).devices;
    final supported = list.where((result) {
      if (result.timeStamp.isBefore(scanStartedAt)) return false;
      if (!result.advertisementData.connectable) return false;
      if (DateTime.now().difference(result.timeStamp) > _visibleDeviceWindow) {
        return false;
      }
      if (!HealthBleService.isSupportedHealthDevice(result)) return false;
      return boundDevices.every(
        (device) => device.id != result.device.remoteId.toString(),
      );
    });

    final next = [..._results];
    for (final result in supported) {
      final index = next.indexWhere(
        (item) => item.device.remoteId == result.device.remoteId,
      );
      if (index >= 0) {
        next[index] = result;
      } else {
        next.add(result);
      }
    }
    final visible = _visibleResults(next);
    if (_sameResults(_results, visible)) return;
    setState(() {
      _results
        ..clear()
        ..addAll(visible);
    });
  }

  List<ScanResult> _visibleResults(List<ScanResult> results) {
    final visible =
        results
            .where(
              (result) =>
                  DateTime.now().difference(result.timeStamp) <=
                  _visibleDeviceWindow,
            )
            .toList()
          ..sort(
            (a, b) => a.device.remoteId.toString().compareTo(
              b.device.remoteId.toString(),
            ),
          );
    return visible;
  }

  Future<void> _connectBindAndSync(ScanResult result) async {
    final remoteId = result.device.remoteId.toString();
    if (_connectingId != null) return;
    final scanStartedAt = _scanStartedAt;
    if (scanStartedAt == null ||
        result.timeStamp.isBefore(scanStartedAt) ||
        !result.advertisementData.connectable ||
        DateTime.now().difference(result.timeStamp) > _visibleDeviceWindow) {
      AppToast.show(context, '设备已离线，请重新进入通信状态', type: AppToastType.warning);
      return;
    }
    if (ref.read(omronDeviceProvider).isBound &&
        ref.read(omronDeviceProvider).findById(remoteId) != null) {
      AppToast.show(context, '该设备已绑定', type: AppToastType.info);
      return;
    }
    setState(() => _connectingId = remoteId);
    await FlutterBluePlus.stopScan();

    final ble = ref.read(healthBleServiceProvider);
    BoundBleDevice? boundDevice;
    try {
      boundDevice = await ble
          .connectAndIdentify(
            device: result.device,
            name: _deviceNameOf(result),
          )
          .timeout(const Duration(seconds: 15));
      if (!HealthBleService.isSyncImplemented(boundDevice.type)) {
        if (mounted) {
          AppToast.show(
            context,
            '${boundDevice.type.label}数据同步暂未开通，暂不绑定',
            type: AppToastType.info,
          );
          unawaited(_startScan());
        }
        return;
      }
      await ref.read(omronDeviceProvider.notifier).bind(boundDevice);

      if (boundDevice.type == BleDeviceType.bloodPressure) {
        final syncResult = await ble.syncBoundDevice(
          result.device,
          boundDevice,
          timeout: const Duration(seconds: 30),
        );
        if (syncResult is BloodPressureSyncResult) {
          final saved = await _persistBloodPressure(
            syncResult.device,
            syncResult.reading,
          );
          if (mounted && saved) {
            await _showBloodPressureDialog(syncResult.reading);
          }
        }
      }

      if (mounted) popRoute(ref);
    } on TimeoutException {
      if (mounted && boundDevice != null) {
        AppToast.show(
          context,
          '${boundDevice.type.label}已绑定，但本次未收到数据',
          type: AppToastType.warning,
        );
        popRoute(ref);
      } else if (mounted) {
        AppToast.show(context, '连接超时，请确认设备仍处于通信状态', type: AppToastType.error);
        unawaited(_startScan());
      }
    } on UnsupportedBleDeviceException catch (e) {
      if (mounted) {
        AppToast.show(context, e.message, type: AppToastType.error);
        unawaited(_startScan());
      }
    } catch (e) {
      if (mounted) {
        AppToast.show(context, '连接失败：$e', type: AppToastType.error);
        unawaited(_startScan());
      }
    } finally {
      await ble.disconnect();
      if (mounted) setState(() => _connectingId = null);
    }
  }

  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) {
    return GradientScaffold(
      appBar: AppBar(
        backgroundColor: Colors.white.withValues(alpha: 0.92),
        elevation: 0,
        title: const Text(
          '新增设备',
          style: TextStyle(color: AppColors.textPrimary),
        ),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back, color: AppColors.textPrimary),
          onPressed: () => popRoute(ref),
        ),
      ),
      body: _results.isEmpty
          ? _ScanningEmpty(animation: _pulseAnim, scanning: _scanning)
          : ListView.separated(
              padding: const EdgeInsets.fromLTRB(16, 12, 16, 20),
              itemCount: _results.length,
              separatorBuilder: (context, index) => const SizedBox(height: 10),
              itemBuilder: (context, index) {
                final result = _results[index];
                return _DeviceResultTile(
                  result: result,
                  connecting:
                      _connectingId == result.device.remoteId.toString(),
                  onConnect: () => _connectBindAndSync(result),
                );
              },
            ),
    );
  }

  String _deviceNameOf(ScanResult result) {
    final advName = result.advertisementData.advName.trim();
    if (advName.isNotEmpty) return advName;
    final platformName = result.device.platformName.trim();
    if (platformName.isNotEmpty) return platformName;
    return HealthBleService.deviceTypeFromScan(result)?.label ?? '健康设备';
  }

  bool _sameResults(List<ScanResult> current, List<ScanResult> next) {
    if (current.length != next.length) return false;
    for (var i = 0; i < current.length; i++) {
      if (current[i].device.remoteId != next[i].device.remoteId) return false;
    }
    return true;
  }

  Future<bool> _ensureBlePermissions() async {
    final statuses = await [
      Permission.bluetoothScan,
      Permission.bluetoothConnect,
    ].request();
    final granted = statuses.values.every((status) => status.isGranted);
    if (granted) return true;
    if (!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;
  }
}

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

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(30),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            _ScanPulse(animation: animation),
            const SizedBox(height: 22),
            Text(
              scanning ? '正在搜索设备' : '暂未发现设备',
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.w800,
                color: AppColors.textPrimary,
              ),
            ),
            const SizedBox(height: 8),
            const Text(
              '请让设备进入通信状态并靠近手机。',
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 14,
                height: 1.45,
                color: AppColors.textSecondary,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _DeviceResultTile extends StatelessWidget {
  final ScanResult result;
  final bool connecting;
  final VoidCallback onConnect;

  const _DeviceResultTile({
    required this.result,
    required this.connecting,
    required this.onConnect,
  });

  @override
  Widget build(BuildContext context) {
    final type = HealthBleService.deviceTypeFromScan(result);
    final name = _deviceNameOf(result, type);
    return Container(
      padding: const EdgeInsets.all(15),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: AppColors.border, width: 1.1),
        boxShadow: [AppTheme.shadowLight],
      ),
      child: Row(
        children: [
          Container(
            width: 48,
            height: 48,
            decoration: BoxDecoration(
              color: AppColors.primary.withValues(alpha: 0.10),
              borderRadius: BorderRadius.circular(14),
              border: Border.all(
                color: AppColors.primary.withValues(alpha: 0.10),
              ),
            ),
            child: Icon(
              type?.icon ?? Icons.bluetooth_rounded,
              color: AppColors.primary,
              size: 25,
            ),
          ),
          const SizedBox(width: 14),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  type?.label ?? '健康设备',
                  style: const TextStyle(
                    fontSize: 18,
                    fontWeight: FontWeight.w800,
                    color: AppColors.textPrimary,
                  ),
                ),
                const SizedBox(height: 4),
                Text(
                  name,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: const TextStyle(
                    fontSize: 14,
                    color: AppColors.textHint,
                  ),
                ),
              ],
            ),
          ),
          const SizedBox(width: 10),
          SizedBox(
            height: 38,
            child: FilledButton(
              onPressed: connecting ? null : onConnect,
              style: FilledButton.styleFrom(
                padding: const EdgeInsets.symmetric(horizontal: 14),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(10),
                ),
                textStyle: const TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w800,
                ),
              ),
              child: Text(connecting ? '连接中' : '连接'),
            ),
          ),
        ],
      ),
    );
  }

  String _deviceNameOf(ScanResult result, BleDeviceType? type) {
    final advName = result.advertisementData.advName.trim();
    if (advName.isNotEmpty) return advName;
    final platformName = result.device.platformName.trim();
    if (platformName.isNotEmpty) return platformName;
    return type?.label ?? '健康设备';
  }
}

class _ScanPulse extends StatelessWidget {
  final Animation<double> animation;

  const _ScanPulse({required this.animation});

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.center,
      children: [
        AnimatedBuilder(
          animation: animation,
          builder: (context, child) => Container(
            width: 78 * animation.value,
            height: 78 * animation.value,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: AppColors.primary.withValues(alpha: 0.08),
            ),
          ),
        ),
        Container(
          width: 64,
          height: 64,
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(20),
            border: Border.all(color: AppColors.borderLight),
          ),
          child: const Icon(
            Icons.bluetooth_searching_rounded,
            size: 32,
            color: AppColors.primary,
          ),
        ),
      ],
    );
  }
}
