package id.kalanusa.flutter_zsdk;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;

import androidx.annotation.NonNull;

import com.zebra.sdk.comm.ConnectionException;
import com.zebra.sdk.printer.discovery.BluetoothDiscoverer;
import com.zebra.sdk.printer.discovery.DiscoveredPrinter;
import com.zebra.sdk.printer.discovery.DiscoveryHandler;

import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;

import id.kalanusa.flutter_zsdk.bluetoothdiscoveryhandler.BluetoothDiscoveryHandler;
import id.kalanusa.flutter_zsdk.bluetoothdiscoveryhandler.BluetoothPrinter;
import io.flutter.Log;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry;

/** FlutterZsdkPlugin */
public class FlutterZsdkPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware, PluginRegistry.RequestPermissionsResultListener {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;
  private Context context;
  private Activity activity;
  private ArrayList<BluetoothPrinter> discoveredPrinterList = new ArrayList<BluetoothPrinter>();
  public static final String bluetoothDiscoveryEventChannel = "id.kalanusa.flutter_zsdk.channel_events/bluetooth_discovery";
  private EventChannel.EventSink attachEvent;
  private Handler handler;
  private DartExecutor dartExecutor;
  private BinaryMessenger binaryMessenger;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_zsdk");
    channel.setMethodCallHandler(this);
    context = flutterPluginBinding.getApplicationContext();
    dartExecutor = Objects.requireNonNull(flutterPluginBinding.getFlutterEngine()).getDartExecutor();
    binaryMessenger = dartExecutor.getBinaryMessenger();

  }

  @Override
  public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
    activity = binding.getActivity();
    binding.addRequestPermissionsResultListener(this);

    new EventChannel(binaryMessenger, bluetoothDiscoveryEventChannel).setStreamHandler(new BluetoothDiscoveryHandler(context, activity));
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {

  }

  @Override
  public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {

  }

  @Override
  public void onDetachedFromActivity() {
    activity = null;
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    switch(call.method) {
      case "findBluetoothPrinters":
        findBluetoothPrinters();
      case "getPlatformVersion":
        Log.w("from native", "TEST");
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }

  @Override
  public boolean onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == 1001) { // Check if it'sthe request we initiated
      if (grantResults.length > 0) {
        boolean bluetoothScanGranted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
        boolean bluetoothConnectGranted = grantResults[1] == PackageManager.PERMISSION_GRANTED;
        boolean locationGranted = grantResults[2] == PackageManager.PERMISSION_GRANTED;

        if (bluetoothScanGranted && bluetoothConnectGranted && locationGranted) {
          // All permissions granted, proceed with Bluetooth operations
          // ... your Bluetooth code here ...
          this.startDiscoverBluetoothPrinters();
        } else {
          System.out.println("Permission Denied, please allow permission to discover bluetooth devices");
          // Handle denied permissions
          // You might display a messageto the user or disable Bluetooth features
          // ... your logic for handling denied permissions ...
        }
      }
    }

    return true;
  }


//  Bluetooth discovery
  public void findBluetoothPrinters() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
      if (context.checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED ||
              context.checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED ||
              context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

        activity.requestPermissions(new String[]{
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT,
                Manifest.permission.ACCESS_FINE_LOCATION
        }, 1001);
      } else {
        this.startDiscoverBluetoothPrinters();
      }
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      if (context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        activity.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1002);
      } else {
        this.startDiscoverBluetoothPrinters();
      }
    }
  }

  public void startDiscoverBluetoothPrinters() {
    new EventChannel(dartExecutor, bluetoothDiscoveryEventChannel).setStreamHandler(
            new EventChannel.StreamHandler() {

              @Override
              public void onListen(Object arguments, EventChannel.EventSink events) {
                Log.w("From native", "Adding Listener");
                attachEvent = events;
                handler = new Handler();
                startDiscoverBluetoothPrintersRunnable.run();
              }

              @Override
              public void onCancel(Object arguments) {
                Log.w("From native", "Cancelling Listener");
                handler.removeCallbacks(startDiscoverBluetoothPrintersRunnable);
                handler = null;
                attachEvent = null;
                System.out.println("StreamHandler - onCanceled: ");              }
            }
    );
  }

//  public void startDiscoverBluetoothPrintersRunnable() {
//    new Thread(new Runnable() {
//      @Override
//      public void run() {
//
//    });
//  }
//
  private final Runnable startDiscoverBluetoothPrintersRunnable = new Runnable() {
    @Override
    public void run() {
      ArrayList<BluetoothPrinter> tempDiscoveredPrinterList = new ArrayList<BluetoothPrinter>();
      DiscoveryHandler discoveryHandler = new DiscoveryHandler() {
        @Override
        public void foundPrinter(DiscoveredPrinter discoveredPrinter) {
          Map<String, String> discoveredPrinterDataMap = discoveredPrinter.getDiscoveryDataMap();
          System.out.println("Found printer "  + discoveredPrinterDataMap.get("FRIENDLY_NAME"));

          BluetoothPrinter bluetoothPrinter = new BluetoothPrinter(discoveredPrinterDataMap.get("FRIENDLY_NAME"), discoveredPrinterDataMap.get("MAC_ADDRESS"));
          tempDiscoveredPrinterList.add(bluetoothPrinter);
          attachEvent.success(tempDiscoveredPrinterList);
        }

        @Override
        public void discoveryFinished() {
          // return value here, this is asynchronous
          Log.w("From Native", "Discovery Success, found "+ tempDiscoveredPrinterList.size() + " Printer(s)");
          attachEvent.endOfStream();
        }

        @Override
        public void discoveryError(String s) {
          System.out.println("Error when discovering bluetooth device");
          System.out.println("message:" + s);
        }
      };

      try {
        BluetoothDiscoverer.findPrinters(context, discoveryHandler);
      } catch (ConnectionException e) {
        System.out.println("Error when finding printers");
//            throw new RuntimeException(e);
      }
    }
  };
}
