import 'dart:io';
import 'dart:typed_data';

import 'package:aman_kassa_flutter/core/base/base_service.dart';
import 'package:bluetooth_print/bluetooth_print.dart';
import 'package:bluetooth_print/bluetooth_print_model.dart';
import 'package:flutter_blue/flutter_blue.dart' as flutter_blue;
import 'package:flutter_blue/gen/flutterblue.pb.dart' as proto;

class BluePrintService extends BaseService {
  final BluetoothPrint _bluetoothAndr = BluetoothPrint.instance;
  flutter_blue.BluetoothDevice? _bluetoothDeviceIOS;
  final flutter_blue.FlutterBlue _bluetoothIOS =
      flutter_blue.FlutterBlue.instance;

  final bool isAndroid = Platform.isAndroid;
  final bool isIos = Platform.isIOS;
  // final bool isAndroid = false;
  // final bool isIos = true;

  BluetoothDevice? _device;

  Future<void> scan() async {
    if (isAndroid) {
      await _bluetoothAndr.startScan(timeout: Duration(seconds: 4));
    } else if (isIos) {
      await _bluetoothIOS.startScan(timeout: const Duration(seconds: 5));
    }
  }

  Future<void> stopScan() async {
    if (isAndroid) {
      await _bluetoothAndr.stopScan();
    } else if (isIos) {
      await _bluetoothIOS.stopScan();
    }
  }

  Stream<List<BluetoothDevice>> get scanResult {
    if (isAndroid)
      return _bluetoothAndr.scanResults;
    else
      return _bluetoothIOS.scanResults.asyncMap<List<BluetoothDevice>>(
          (event) =>
              Future.wait(event.toList().map((e) async => BluetoothDevice()
                ..name = e.device.name
                ..type = e.device.type.index
                ..address = e.device.id.id)));
  }

  Stream<bool> get isScanning =>
      isAndroid ? _bluetoothAndr.isScanning : _bluetoothIOS.isScanning;

  Stream<int> get state => isAndroid
      ? _bluetoothAndr.state
      : _bluetoothIOS.state.asyncMap<int>((event) => event.index);

  set device(BluetoothDevice device) => _device = device;

  Future<bool> connect() async {
    bool response = false;
    if (_device == null) {
      response = false;
    } else {
      // try {
      //   await _bluetoothAndr.connect(_device!);
      //   await Future.delayed(Duration(seconds: 5));
      //   response = true;
      // } catch (e) {
      //   print('Error connect $e');
      //   response = false;
      // }

      try {
        if (isAndroid) {
          await _bluetoothAndr.connect(_device!);
        } else if (isIos) {
          _bluetoothDeviceIOS = flutter_blue.BluetoothDevice.fromProto(
            proto.BluetoothDevice(
              name: _device?.name ?? '',
              remoteId: _device?.address ?? '',
              type: proto.BluetoothDevice_Type.valueOf(_device?.type ?? 0),
            ),
          );
          final List<flutter_blue.BluetoothDevice> connectedDevices =
              await _bluetoothIOS.connectedDevices;
          final int deviceConnectedIndex = connectedDevices
              .indexWhere((flutter_blue.BluetoothDevice bluetoothDevice) {
            return bluetoothDevice.id == _bluetoothDeviceIOS?.id;
          });
          if (deviceConnectedIndex < 0) {
            await _bluetoothDeviceIOS?.connect();
          }
        }

        response = true;
        _device?.connected = true;
        return Future<bool>.value(response);
      } on Exception catch (error) {
        print('$runtimeType - Error $error');
        response = false;
        _device?.connected = false;
        return Future<bool>.value(response);
      }
    }
    return response;
  }

  Future<bool> disconnect() async {
    bool response = false;
    try {
      if (isAndroid) {
        await _bluetoothAndr.disconnect();
      } else if (isIos) {
        await _bluetoothDeviceIOS?.disconnect();
      }

      print('disconnected');
      response = true;
    } catch (e) {
      print('Error $e');
      response = false;
    }
    return response;
  }

  Future<bool> printBytes(Uint8List bytes,
      {int chunkSizeBytes = 20, int queueSleepTimeMs = 20}) async {
    Map<String, dynamic> config = Map();
    final len = bytes.length;
    List<List<int>> chunks = [];
    for (var i = 0; i < len; i += chunkSizeBytes) {
      var end = (i + chunkSizeBytes < len) ? i + chunkSizeBytes : len;
      chunks.add(bytes.sublist(i, end));
    }

    for (var i = 0; i < chunks.length; i += 1) {
      if (isAndroid) {
        await _printAndroid(chunks[i], config);
      } else if (isIos) {
        await _printIos(Uint8List.fromList(chunks[i]), config);
      }

      await Future.delayed(Duration(milliseconds: queueSleepTimeMs));
    }



    return true;
  }

  Future<void> _printIos(Uint8List bytes,Map<String, dynamic> config) async {
    final List<flutter_blue.BluetoothService> bluetoothServices =
        await _bluetoothDeviceIOS?.discoverServices() ??
            <flutter_blue.BluetoothService>[];
    final flutter_blue.BluetoothService bluetoothService =
        bluetoothServices.firstWhere(
      (flutter_blue.BluetoothService service) => service.isPrimary,
    );
    final flutter_blue.BluetoothCharacteristic characteristic =
        bluetoothService.characteristics.firstWhere(
      (flutter_blue.BluetoothCharacteristic bluetoothCharacteristic) =>
          bluetoothCharacteristic.properties.write,
    );
    await characteristic.write(bytes, withoutResponse: true);
  }

  Future<void> _printAndroid(List<int> chunk ,Map<String, dynamic> config) async {


    await _bluetoothAndr.rawBytes(config, chunk);
  }
}
