import 'dart:async';
import 'dart:convert';
import 'dart:io';

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

import '../constants.dart';
import '../models/device_model.dart';
import '../models/device_config_model.dart'; // WICHTIG: Korrekter Import

class DeviceProvider extends ChangeNotifier {
  final List<LasertagDevice> _discoveredLeaders = [];
  final List<LasertagDevice> _discoveredPeripherals = [];
  StreamSubscription? _scanSubscription;
  DeviceConfig? _activeConfig;
  DeviceConfig? get activeConfig => _activeConfig;

  List<LasertagDevice> get leaders => _discoveredLeaders;
  List<LasertagDevice> get peripherals => _discoveredPeripherals;

  void setActiveConfig(DeviceConfig config) {
    _activeConfig = config;
    notifyListeners();
  } 

  Future<void> provisionWithActiveConfig(LasertagDevice device, {bool keepName = true}) async {
    if (_activeConfig == null) throw Exception("Keine aktive Konfiguration vorhanden");
    DeviceConfig configToUse = _activeConfig!;
    if (keepName) {
      configToUse = configToUse.copyWith(
        nodeName: device.name,
        systemState: LasertagConfig.sysStateLobby,
      );
    }
    await provisionDevice(device, configToUse);
  }

  Future<void> batchProvisionFoundDevices() async {
    // 1. Scan für 10 Sekunden starten
    startScan();
    await Future.delayed(const Duration(seconds: 10));
    await FlutterBluePlus.stopScan();

    // 2. Alle gefundenen Peripherals provisionieren
    for (var device in _discoveredPeripherals) {
      try {
        await provisionWithActiveConfig(device, keepName: true);
        debugPrint("Provisioniert: ${device.name}");
      } catch (e) {
        debugPrint("Fehler bei ${device.name}: $e");
      }
    }
  }

  void startScan() async {
    _discoveredLeaders.clear();
    _discoveredPeripherals.clear();
    notifyListeners();
    await FlutterBluePlus.stopScan();
    await FlutterBluePlus.adapterState.where((s) => s == BluetoothAdapterState.on).first;
    _scanSubscription?.cancel();
    _scanSubscription = FlutterBluePlus.scanResults.listen((results) {
      for (ScanResult r in results) {
        bool hasService = r.advertisementData.serviceUuids.contains(Guid(LasertagConfig.provService));
        if (!hasService) continue;
        final mfgData = r.advertisementData.manufacturerData[65535];
        if (mfgData != null && mfgData.isNotEmpty) {
          final device = LasertagDevice(
            id: r.device.remoteId.toString(),
            name: r.device.platformName.isEmpty ? "Unbekannt" : r.device.platformName,
            type: mfgData[0],
            btDevice: r.device,
            isConnected: false,
            isNameVerified: false,
          );
          _addDeviceToLists(device);
        }
      }
    });
    try { await FlutterBluePlus.startScan(timeout: const Duration(seconds: 15)); } catch (e) { debugPrint("Scan-Fehler: $e"); }
  }

  Future<String> readDeviceNameFromHardware(LasertagDevice ltDevice) async {
    try {
      if (!ltDevice.btDevice.isConnected) {
        await ltDevice.btDevice.connect(license: License.free, timeout: const Duration(seconds: 5));
      }
      List<BluetoothService> srv = await ltDevice.btDevice.discoverServices();
      var c = srv.firstWhere((s) => s.uuid == Guid(LasertagConfig.provService))
                 .characteristics.firstWhere((c) => c.uuid == Guid(LasertagConfig.provNameChar));
      List<int> value = await c.read();
      String hardwareName = utf8.decode(value);
      updateDeviceName(ltDevice.id, hardwareName, verified: true);
      return hardwareName;
    } finally { await ltDevice.btDevice.disconnect(); }
  }

  Future<void> updateDeviceNameOnHardware(LasertagDevice ltDevice, String newName) async {
    try {
      await ltDevice.btDevice.connect(license: License.free, timeout: const Duration(seconds: 10));
      List<BluetoothService> srv = await ltDevice.btDevice.discoverServices();
      var c = srv.firstWhere((s) => s.uuid == Guid(LasertagConfig.provService))
                 .characteristics.firstWhere((c) => c.uuid == Guid(LasertagConfig.provNameChar));
      await c.write(utf8.encode(newName));
      updateDeviceName(ltDevice.id, newName, verified: true);
    } finally { await ltDevice.btDevice.disconnect(); }
  }

  // Die neuen optimierten Methoden
  Future<DeviceConfig> readDeviceConfig(LasertagDevice device) async {
    try {
      if (!device.btDevice.isConnected) {
        await device.btDevice.connect(license: License.free, timeout: const Duration(seconds: 10));
      }
      List<BluetoothService> srv = await device.btDevice.discoverServices();
      var c = srv.firstWhere((s) => s.uuid == Guid(LasertagConfig.provService))
                 .characteristics.firstWhere((c) => c.uuid == Guid(LasertagConfig.provConfigChar));
      final bytes = await c.read();
      return DeviceConfig.fromBytes(bytes);
    } finally { await device.btDevice.disconnect(); }
  }

  Future<void> provisionDevice(LasertagDevice device, DeviceConfig config, {bool keepConnected = false}) async {
    try {
      if (!device.btDevice.isConnected) {
        await device.btDevice.connect(license: License.free, timeout: const Duration(seconds: 10));
      }

      if (Platform.isAndroid) {
        try {
          await device.btDevice.requestMtu(250);
          // await Future.delayed(const Duration(milliseconds: 200));
        } catch (e) {
          debugPrint("MTU Request failed (Android only): $e");
        }
      }

      List<BluetoothService> srv = await device.btDevice.discoverServices();
      var c = srv
          .firstWhere((s) => s.uuid == Guid(LasertagConfig.provService))
          .characteristics
          .firstWhere((c) => c.uuid == Guid(LasertagConfig.provConfigChar));

      await c.write(config.toBytes(), allowLongWrite: true);
      updateDeviceName(device.id, config.nodeName, verified: true);
    } catch (e) {
      await device.btDevice.disconnect();
      rethrow;
    } finally {
      if (!keepConnected) {
        await device.btDevice.disconnect();
      }
    }
  }

  // ... Hilfsmethoden updateDeviceName, _addDeviceToLists, _verifyNameInBackground (mit license!), _sortList etc. bleiben ...
  void updateDeviceName(String id, String newName, {bool verified = false}) {
    _updateDeviceInLists(id, (old) => old.copyWith(name: newName, isNameVerified: verified));
  }

  void _addDeviceToLists(LasertagDevice device) {
    List<LasertagDevice> list = device.isLeader ? _discoveredLeaders : _discoveredPeripherals;
    if (!list.any((d) => d.id == device.id)) {
      list.add(device);
      _sortList(list);
      notifyListeners();
      _verifyNameInBackground(device);
    }
  }

  Future<void> _verifyNameInBackground(LasertagDevice device) async {
    if (device.isNameVerified) return;
    try {
      await device.btDevice.connect(license: License.free, timeout: const Duration(seconds: 5));
      List<BluetoothService> services = await device.btDevice.discoverServices();
      var characteristic = services.firstWhere((s) => s.uuid == Guid(LasertagConfig.provService))
                                    .characteristics.firstWhere((c) => c.uuid == Guid(LasertagConfig.provNameChar));
      List<int> value = await characteristic.read();
      updateDeviceName(device.id, utf8.decode(value), verified: true);
    } catch (e) {
      debugPrint("Background Sync fehlgeschlagen für ${device.id}");
    } finally { await device.btDevice.disconnect(); }
  }

  void _updateDeviceInLists(String id, LasertagDevice Function(LasertagDevice) updateFn) {
    for (var list in [_discoveredLeaders, _discoveredPeripherals]) {
      int index = list.indexWhere((d) => d.id == id);
      if (index != -1) {
        list[index] = updateFn(list[index]);
        _sortList(list);
        notifyListeners();
        return;
      }
    }
  }

  void _sortList(List<LasertagDevice> list) {
    list.sort((a, b) {
      int typeComp = a.type.compareTo(b.type);
      if (typeComp != 0) return typeComp;
      return a.name.toLowerCase().compareTo(b.name.toLowerCase());
    });
  }

  @override
  void dispose() {
    _scanSubscription?.cancel();
    super.dispose();
  }
}