package com.cxview.media_palyer_client;

import com.getcapacitor.JSObject;
import com.getcapacitor.Plugin;
import com.getcapacitor.NativePlugin;
import com.getcapacitor.PluginCall;
import com.getcapacitor.PluginMethod;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.HashSet;

@NativePlugin()
public class SearchDevicePlugin extends Plugin {
  private static final String TAG = "SearchDevicePlugin";
  DatagramSocket udp_socket = null;
  boolean exit_flag = false;

  HashSet<String> ip_addresses = new HashSet<>();

  public SearchDevicePlugin() {
    super();
    try {
      udp_socket = new DatagramSocket();
      new Thread(() -> {
        final int  kPacketSize = 4 + 4 + 4 + 1 + 33 + 33;

        byte[] buf = new byte[1024 * 1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        try {
          while (!exit_flag) {
            udp_socket.receive(packet);
            if (packet.getLength() > 79) {
              DataInputStream dis = new DataInputStream(new ByteArrayInputStream(packet.getData()));
              int magic_flag = reversalEndian(dis.readInt());
              if(magic_flag == 0xEA86EA86) {
                int version = reversalEndian(dis.readInt());
                int data_length = reversalEndian(dis.readInt());
                if(data_length + kPacketSize == packet.getLength()) {
                  byte crc = dis.readByte();
                  dis.skipBytes(33 + 33);
                  byte[] json_data = new byte[packet.getLength() - kPacketSize];
                  int ret_size = dis.read(json_data);
                  if(ret_size == json_data.length) {
                    String json_string = new String(json_data, 0, ret_size);
                    if(getCheckAddAll(json_string) == crc) {
                      try {
                        JSONObject json = new JSONObject(json_string);
                        if(json.get("command").equals("_SearchDevice")) {
                          ip_addresses.add(packet.getAddress().getHostAddress());
                        }
                      } catch (JSONException e) {
                        e.printStackTrace();
                      }
                    }
                  }
                }
              }
            }
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
      }).start();
    } catch (SocketException e) {
      e.printStackTrace();
    }
  }

  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    exit_flag = true;
  }

  @PluginMethod()
  public void searchDevice(PluginCall call) {
    // More code here...
    ip_addresses.clear();

    JSObject obj = new JSObject();
    try {
      JSObject o = new JSObject();
      o.put("has_exception", false);
      o.put("flag", 0); // 0 请求 1响应
      o.put("rpc_id", 0);
      o.put("command", "_SearchDevice");
      o.put("device_type", "RK3568");

      String output_str = o.toString();

      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      DataOutputStream dos = new DataOutputStream(bos);
      dos.writeInt(reversalEndian(0xEA86EA86));
      dos.writeInt(reversalEndian(0));
      dos.writeInt(reversalEndian(output_str.length()));
      dos.writeByte(getCheckAddAll(output_str));
      byte[] zero = new byte[33];
      dos.write(zero);
      dos.write(zero);
      dos.writeBytes(output_str);
      byte[] data = bos.toByteArray();
      try {
        udp_socket.send(new DatagramPacket(data, data.length, InetAddress.getByName("255.255.255.255"), 60427));
        udp_socket.send(new DatagramPacket(data, data.length, InetAddress.getByName("255.255.255.255"), 61427));
      } catch (IOException e) {
        e.printStackTrace();
      }
    } catch (IOException e) {
      e.printStackTrace();
    }

    try {
      Thread.sleep(1000 * 5);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    StringBuffer buffer = new StringBuffer();
    buffer.append("[");
    for(String ip : ip_addresses) {
      buffer.append("\"");
      buffer.append(ip);
      buffer.append("\",");
    }
    buffer.delete(buffer.length() - 1, buffer.length());
    buffer.append("]");
    obj.put("ip_list", buffer);
    call.resolve(obj);
  }

  static byte getCheckAddAll(String str) {
    byte calc_value = 0;

    for (int i = 0; i < str.length(); ++i) {
      calc_value += str.charAt(i);
    }

    return calc_value;
  }

  public static int reversalEndian(int i) {
    byte[] b = new byte[4];
    b[0] = (byte) (0xff & i);
    b[1] = (byte) ((0xff00 & i) >> 8);
    b[2] = (byte) ((0xff0000 & i) >> 16);
    b[3] = (byte) ((0xff000000 & i) >> 24);
    return b[3] & 0xFF | (b[2] & 0xFF) << 8 | (b[1] & 0xFF) << 16
      | (b[0] & 0xFF) << 24;
  }

}
