package com.vispec.sdkdemo;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import pub.devrel.easypermissions.AppSettingsDialog;
import pub.devrel.easypermissions.EasyPermissions;
import pub.devrel.easypermissions.PermissionRequest;

import android.Manifest;
import android.app.VoiceInteractor;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent;
import android.gesture.GestureOverlayView;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.impl.LoadingPopupView;
import com.vispec.sdklibrary.CodeResponse;
import com.vispec.sdklibrary.bluetooth.connect.listener.BleConnectStatusListener;
import com.vispec.sdklibrary.bluetooth.connect.listener.BluetoothStateListener;
import com.vispec.sdklibrary.bluetooth.connect.options.BleConnectOptions;
import com.vispec.sdklibrary.bluetooth.connect.response.BleConnectResponse;
import com.vispec.sdklibrary.bluetooth.connect.response.BleWriteResponse;
import com.vispec.sdklibrary.bluetooth.model.BleGattProfile;
import com.vispec.sdklibrary.bluetooth.search.SearchRequest;
import com.vispec.sdklibrary.bluetooth.search.SearchResult;
import com.vispec.sdklibrary.bluetooth.search.response.SearchResponse;
import com.vispec.sdklibrary.bluetooth.utils.BluetoothLog;
import com.vispec.sdklibrary.bluetooth.utils.SendCodeUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.IllegalFormatCodePointException;
import java.util.List;

import static com.vispec.sdklibrary.bluetooth.Code.REQUEST_SUCCESS;
import static com.vispec.sdklibrary.bluetooth.Constants.CODE_CONNECT;
import static com.vispec.sdklibrary.bluetooth.Constants.STATUS_CONNECTED;
import static com.vispec.sdklibrary.bluetooth.Constants.STATUS_DEVICE_CONNECTED;

public class MainActivity extends AppCompatActivity implements View.OnClickListener,EasyPermissions.PermissionCallbacks,CommonPopupWindow.ViewInterface {
    TextView tvConnect;
    private List<SearchResult> deviceList = new ArrayList<>();
    private XPopup.Builder xpopBuilder;
    private LoadingPopupView loadingPopupView;
    private CommonPopupWindow popupWindow;
    private TextView tvDialogTitle;
    private RecyclerView rcvDevice;
    private LinearLayout llNoDevice;
    private ImageView ivLoading;
    private DeviceAdapter deviceAdapter;
    private String blueToothAddress;
    private boolean mConnected;
    private String blueToothName;
    private TextView tvDeviceNo,tvTemperature,tvElec,tvVersion,tvScanResult,tvScanReferenceResult,tvScanResultOneByOne;
    private static final String[] PERMIS = {Manifest.permission.BLUETOOTH,Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION};
    private int ledCount = 22;
    private int count;
    private StringBuffer buffer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvConnect = findViewById(R.id.tv_connect);
        tvConnect.setOnClickListener(this);
        findViewById(R.id.btn_get_device_no).setOnClickListener(this);
        tvDeviceNo = findViewById(R.id.tv_device_no);
        findViewById(R.id.btn_get_temperature).setOnClickListener(this);
        tvTemperature = findViewById(R.id.tv_temperature);
        findViewById(R.id.btn_get_elec).setOnClickListener(this);
        tvElec = findViewById(R.id.tv_elec);
        findViewById(R.id.btn_get_version).setOnClickListener(this);
        tvVersion = findViewById(R.id.tv_version);
        findViewById(R.id.btn_scan).setOnClickListener(this);
        tvScanResult = findViewById(R.id.tv_scan_result);
        tvScanReferenceResult = findViewById(R.id.tv_scan_referenc_result);
        findViewById(R.id.btn_scan_one_by_one).setOnClickListener(this);
        tvScanResultOneByOne = findViewById(R.id.tv_scan_one_by_one_result);

        xpopBuilder = new XPopup.Builder(this).dismissOnBackPressed(true).dismissOnTouchOutside(false);


    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.tv_connect:
                if (!mConnected){
                    judgePermissions();
                }else {
                    disConnectBlueTooth();
                }
                break;
            case R.id.tv_cancel:
                if (popupWindow != null && popupWindow.isShowing()){
                    popupWindow.dismiss();
                }
                break;
            case R.id.btn_get_device_no:
                //发送获取设备编号指令
                sendCodeIfNeeded(SendCodeUtils.getDeviceSNCode(),true);
                break;
            case R.id.btn_get_temperature:
                //发送获取温度指令
                sendCodeIfNeeded(SendCodeUtils.getTemCode(),true);
                break;
            case R.id.btn_get_elec:
                //发送获取电量指令
                sendCodeIfNeeded(SendCodeUtils.getElecCode(),true);
                break;
            case R.id.btn_get_version:
                //发送获取硬件版本指令
                sendCodeIfNeeded(SendCodeUtils.getDeviceVersionCode(),true);
                break;
            case R.id.btn_scan:
                //发送获取光谱值指令
                sendCodeIfNeeded(SendCodeUtils.getScanResultCode(blueToothName),true);
                break;
            case R.id.btn_scan_one_by_one:
                //一个灯一个灯发送获取光谱值指令，不常用
                count = 1;
                sendCodeIfNeeded(SendCodeUtils.getScanResultCodeOneByOne(blueToothName,count),true);
                break;
        }
    }

    /**
     * 发送指令
     * @param code
     */
    private void sendCodeIfNeeded(byte[] code,boolean isShowLoading){
        if (!mConnected){
            Toast.makeText(this,"请先连接蓝牙",Toast.LENGTH_SHORT).show();
            return;
        }
        if (MyApplication.mClient!= null && !TextUtils.isEmpty(blueToothAddress)){
            if (isShowLoading) {
                loadingPopupView = xpopBuilder.asLoading("请稍后...");
                loadingPopupView.show();
            }
            SendCodeUtils.sendCode(MyApplication.mClient, blueToothAddress,code, bleWriteResponse);
        }
    }

    private BleWriteResponse bleWriteResponse = new BleWriteResponse() {
        @Override
        public void onResponse(int code) {
            if (code != REQUEST_SUCCESS){
                if (loadingPopupView != null){
                    loadingPopupView.dismiss();
                }
                Toast.makeText(MainActivity.this,"指令发送失败",Toast.LENGTH_SHORT).show();
            }
        }
    };

    /**
     * 蓝牙连接状态监听
     */
    private final BleConnectStatusListener mConnectStatusListener = new BleConnectStatusListener() {
        @Override
        public void onConnectStatusChanged(String mac, int status) {
            BluetoothLog.v(String.format("DeviceDetailActivity onConnectStatusChanged %d in %s",
                    status, Thread.currentThread().getName()));

            mConnected = (status == STATUS_CONNECTED);
            tvConnect.setText(mConnected?"断开蓝牙"+blueToothName:"连接蓝牙");
            if (mConnected){
                Toast.makeText(MainActivity.this,"蓝牙连接成功",Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(MainActivity.this,"蓝牙已断开",Toast.LENGTH_SHORT).show();
            }
            if (loadingPopupView != null){
                loadingPopupView.dismiss();
            }
            if (mConnected){
                CodeResponse codeResponse = new CodeResponse(MyApplication.mClient,blueToothAddress);
                codeResponse.registCodeResponseListener((mark, data) -> {
                    if (loadingPopupView != null ){
                        if (mark != CodeResponse.CODE_RESPONSE_SCAN_ONE_BY_ONE){
                            loadingPopupView.dismiss();
                        }else if (count == ledCount){
                            loadingPopupView.dismiss();
                        }
                    }
                    switch (mark){
                        case CodeResponse.CODE_RESPONSE_DEVICE_NO:
                            tvDeviceNo.setText(data);
                            break;
                        case CodeResponse.CODE_RESPONSE_ELEC:
                            tvElec.setText(data);
                            break;
                        case CodeResponse.CODE_RESPONSE_TEMPERATURE:
                            tvTemperature.setText(data);
                            break;
                        case CodeResponse.CODE_RESPONSE_VERSION:
                            tvVersion.setText(data);
                            break;
                        case CodeResponse.CODE_RESPONSE_SCAN:
                            tvScanResult.setText("实际值："+data);
                            break;
                        case CodeResponse.CODE_RESPONSE_SCAN_REFERENCE:
                            tvScanReferenceResult.setText("参比值："+data);
                            break;
                        case CodeResponse.CODE_RESPONSE_SCAN_ONE_BY_ONE:
                            if (count == 1){
                                buffer = new StringBuffer();
                            }
                            if (buffer != null){
                                buffer.append(data);
                                buffer.append(",");
                            }
                            tvScanResultOneByOne.setText(count == ledCount?buffer.substring(0,buffer.length()-1):buffer.toString());
                            if (count >= ledCount){
                                return;
                            }
                            count++;
                            sendCodeIfNeeded(SendCodeUtils.getScanResultCodeOneByOne(blueToothName,count),false);
                            break;
                    }
                });

            }
        }
    };
    public boolean getGPSStates(){
        LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }
    private void judgePermissions(){
        if (!getGPSStates()){
            Toast.makeText(this,"请下拉通知栏打开位置信息开关",Toast.LENGTH_SHORT).show();
            return;
        }
        if (!BluetoothAdapter.getDefaultAdapter().isEnabled()){
            Toast.makeText(this,"请下拉通知栏打开蓝牙",Toast.LENGTH_SHORT).show();
            return;
        }
        if (EasyPermissions.hasPermissions(this,PERMIS)){
            searchDevice();
        }else {
            EasyPermissions.requestPermissions(this,"蓝牙需要定位权限",1000,PERMIS);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        EasyPermissions.onRequestPermissionsResult(requestCode,permissions,grantResults,this);
    }
    @Override
    public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
        if (perms.size() == PERMIS.length){
            searchDevice();
        }
    }

    @Override
    public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
        if (EasyPermissions.somePermissionPermanentlyDenied(this,perms)){
            new AppSettingsDialog.Builder(this).build().show();
        }
    }


    /**
     * 搜索蓝牙
     */
    private void searchDevice() {
        deviceList.clear();
        SearchRequest request = new SearchRequest.Builder()
                .searchBluetoothLeDevice(5000, 2).build();

        MyApplication.mClient.search(request, mSearchResponse);
    }

    private final SearchResponse mSearchResponse = new SearchResponse() {
        @Override
        public void onSearchStarted() {
            BluetoothLog.w("MainActivity.onSearchStarted");
            showPop(R.layout.dialog_search_device);

        }

        @Override
        public void onDeviceFounded(SearchResult device) {
            String name = device.getName();
            Log.e("蓝牙",name+"...");
            if (!deviceList.contains(device)){
                deviceList.add(device);
                deviceAdapter.notifyDataSetChanged();
                tvDialogTitle.setText("选择可用设备");
            }
            if (deviceList.size() == 1){
                loadingStop();
                llNoDevice.setVisibility(View.GONE);
                rcvDevice.setVisibility(View.VISIBLE);
            }
        }

        @Override
        public void onSearchStopped() {
            BluetoothLog.w("MainActivity.onSearchStopped");
            if (deviceList.isEmpty()){
                llNoDevice.setVisibility(View.VISIBLE);
                tvDialogTitle.setVisibility(View.INVISIBLE);
                loadingStop();
                rcvDevice.setVisibility(View.GONE);
            }
        }

        @Override
        public void onSearchCanceled() {
            BluetoothLog.w("MainActivity.onSearchCanceled");

        }
    };

    /**
     * 连接蓝牙
     * @param address
     */
    private void connectDeviceIfNeeded(String address){
        if (mConnected)return;
        if (MyApplication.mClient.getConnectStatus(address) == STATUS_DEVICE_CONNECTED ){
            Toast.makeText(this,"蓝牙设备已经被其它应用连接，请先断开再连接",Toast.LENGTH_SHORT).show();
            return;
        }
        LoadingPopupView loadingPopupView = xpopBuilder.asLoading("连接中...");
        loadingPopupView.show();
        MyApplication.mClient.registerConnectStatusListener(address,mConnectStatusListener);
        BleConnectOptions options = new BleConnectOptions.Builder()
                .setConnectRetry(3)
                .setConnectTimeout(20000)
                .setServiceDiscoverRetry(3)
                .setServiceDiscoverTimeout(10000)
                .build();

        MyApplication.mClient.connect(address, options, new BleConnectResponse() {
            @Override
            public void onResponse(int code, BleGattProfile profile) {
                BluetoothLog.v(String.format("profile:\n%s", profile));
                if (code == REQUEST_SUCCESS){
                    loadingPopupView.dismiss();
                }
            }
        });
    }

    /**
     * 断开蓝牙
     */
    private void disConnectBlueTooth(){
        if (!TextUtils.isEmpty(blueToothAddress)){
            MyApplication.mClient.disconnect(blueToothAddress);
            MyApplication.mClient.refreshCache(blueToothAddress);
        }
    }

    @Override
    protected void onDestroy() {
        disConnectBlueTooth();
        MyApplication.mClient.unregisterConnectStatusListener(blueToothAddress,mConnectStatusListener);
        super.onDestroy();
    }

    @Override
    protected void onPause() {
        super.onPause();
        MyApplication.mClient.stopSearch();
    }

    public void showPop(int popLayout){
        popupWindow = new CommonPopupWindow.Builder(this)
                //设置PopupWindow布局
                .setView(popLayout)
                //设置宽高
                .setWidthAndHeight(  ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT)
                //设置动画
               // .setAnimationStyle(R.style.picker_view_filter_anim)
                //设置背景颜色，取值范围0.0f-1.0f 值越小越暗 1.0f为透明
                .setBackGroundLevel(0.4f)
                .setViewOnclickListener(this)
                //设置外部是否可点击 默认是true
                .setOutsideTouchable(false)
                //开始构建
                .create();
        //弹出PopupWindow
        popupWindow.showAtLocation(tvConnect, Gravity.BOTTOM,0, 0);
    }

    @Override
    public void getChildView(View view, int layoutResId) {
        switch (layoutResId){
            case R.layout.dialog_search_device:
                view.findViewById(R.id.tv_cancel).setOnClickListener(this);
                tvDialogTitle = view.findViewById(R.id.tv_dialog_title);
                rcvDevice = view.findViewById(R.id.rcv_device);
                llNoDevice = view.findViewById(R.id.ll_no_device);
                ivLoading = view.findViewById(R.id.iv_loading);
                deviceList.clear();
                initRecycleviewDevice();
                loadingStart();
                break;
        }
    }

    private void loadingStart(){
        if (ivLoading == null)return;
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.jiazai_item);
        animation.setInterpolator(new LinearInterpolator());
        ivLoading.startAnimation(animation);
    }
    private void loadingStop(){
        if (ivLoading == null)return;
        ivLoading.clearAnimation();
        ivLoading.setVisibility(View.GONE);
    }

    private void initRecycleviewDevice(){
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        rcvDevice.setLayoutManager(linearLayoutManager);
        deviceAdapter = new DeviceAdapter(R.layout.rcv_item_device,deviceList);
        rcvDevice.setAdapter(deviceAdapter);
        deviceAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
                blueToothAddress = ((SearchResult) adapter.getItem(position)).getAddress();
                blueToothName = ((SearchResult) adapter.getItem(position)).getName();
                connectDeviceIfNeeded(blueToothAddress);
                if (popupWindow != null && popupWindow.isShowing()){
                    popupWindow.dismiss();
                }
            }
        });
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (popupWindow!= null && popupWindow.isShowing()){
            return false;
        }
        return super.dispatchTouchEvent(ev);
    }


}