package cgmblelib.ble.reconnectManagament;

import android.os.Build;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.TimeUnit;

import cgmblelib.base.BApplication;
import cgmblelib.ble.BleService;
import cgmblelib.ble.gattcallback.ManageGattCallback;
import cgmblelib.ble.scancallback.ManageScanCallback;
import cgmblelib.custom.livedata.ManagementLiveData;
import cgmblelib.custom.livedata.scan.EnumScan;
import cgmblelib.database.entity.PocDevice;
import cgmblelib.database.repository.RepositoryDevice;
import cgmblelib.utils.ConstantsLibrary;
import cgmblelib.utils.MyLog;
import cgmblelib.utils.PermissionCheckTool;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

/**
 * 重新连接管理类
 * 当APP类似于首次开启式,进行搜索后再尝试连接，
 * 若APP搜索是搜索到了发射器，但是连接失败，此时可以尝试使用mac地址连接
 * 若使用mac地址连接多次连接失败，转搜索连接
 *
 * @author minyuchun
 * 默认的方式
 */
public class ReconnectManagement implements BaseReconnect {

    private Disposable mDisposable;

    /**
     * 搜索的间隔时间
     */
    public static final long TIME_INTERVAL_RECONNECT = 40 * 1000;
    /**
     * 重新连接的间隔时间
     */
    public static final long TIME_INTERVAL_RECONNECT_GATT = 40 * 1000;
    /**
     * 连接超时的间隔时间
     */
    public static final long TIME_INTERVAL_RECONNECT_GATT_TIMEOUT = 20 * 1000;

    private PermissionCheckTool permissionCheckTool;

    /**
     * 初始化数据
     *
     * @param service 服务
     */
    public void init(@NonNull BleService service) {
        permissionCheckTool = new PermissionCheckTool(service);
    }

    private boolean isBtConnectPermissionLocks() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (permissionCheckTool != null) {
                return permissionCheckTool.lacksPermissions(ConstantsLibrary.BLUETOOTH_S);
            }
        }
        return false;
    }

    @Override
    public void reconnectViaScan(PocDevice device) {
        MyLog.iLog("reconnectViaScan");
        if (isBtConnectPermissionLocks()) {
            //没有GPS的权限
            MyLog.i("未获取蓝牙连接权限");
            ManagementLiveData.getInstance().updateOperationScan(EnumScan.SCAN_ERROR_CONNECT_OFF);
        } else {
            ManageScanCallback.getInstance().reConnectViaScan(device);
        }
    }

    @Override
    public void reconnectViaCache(PocDevice device) {
        MyLog.iLog("reconnectViaCache");
        if (isBtConnectPermissionLocks()) {
            //没有GPS的权限
            MyLog.i("未获取蓝牙连接权限");
            ManagementLiveData.getInstance().updateOperationScan(EnumScan.SCAN_ERROR_CONNECT_OFF);
        } else {
            ManageGattCallback.getInstance().reConnectViaCache(device);
        }
    }

    @Override
    public void reconnectViaNew(PocDevice device) {
        MyLog.iLog("reconnectViaNew");
        if (isBtConnectPermissionLocks()) {
            //没有GPS的权限
            MyLog.i("未获取蓝牙连接权限");
            ManagementLiveData.getInstance().updateOperationScan(EnumScan.SCAN_ERROR_CONNECT_OFF);
        } else {
            ManageGattCallback.getInstance().reConnectViaNew(device);
        }

    }

    @Override
    public void stopReconnect() {
        if (mDisposable != null && !mDisposable.isDisposed()) {
            mDisposable.dispose();
        }
    }

    @IntDef({ReconnectState.STATE_BLUETOOTH_ON, ReconnectState.STATE_APP_ON, ReconnectState.STATE_SCAN,
            ReconnectState.STATE_PERMISSION, ReconnectState.STATE_RECONNECT, ReconnectState.STATE_NEW_GATT,
            ReconnectState.STATE_SCAN_AUTO, ReconnectState.STATE_SCAN_AGAIN, ReconnectState.STATE_CONNECTION_DELAY})
    @Retention(RetentionPolicy.SOURCE)
    public @interface ReconnectState {
        /**
         * 开启蓝牙时
         */
        public int STATE_BLUETOOTH_ON = 1;
        /**
         * 打开APP时
         */
        public int STATE_APP_ON = 2;
        /**
         * 点击重连时候
         */
        public int STATE_SCAN = 3;
        /**
         * 在主界面重新获得权限时
         */
        public int STATE_PERMISSION = 4;
        /**
         * 断开连接后重新连接时
         */
        public int STATE_RECONNECT = 5;
        /**
         * 新建GATT连接
         */
        public int STATE_NEW_GATT = 6;
        /**
         * 自动转换成搜索重连
         */
        public int STATE_SCAN_AUTO = 7;
        /**
         * 非重连机制，只是进行发射器搜索
         */
        public int STATE_SCAN_AGAIN = 11;

        public int STATE_CONNECTION_DELAY = 100;
    }

    ReconnectManagement() {
    }

    private static class SingletonInstance {
        private static final ReconnectManagement INSTANCE = new ReconnectManagement();
    }

    public static ReconnectManagement getInstance() {
        return SingletonInstance.INSTANCE;
    }


    public void reconnect(int state) {
        if (ConstantsLibrary.TIME_SECONDS_DISCONNECT > 0 && state == ReconnectState.STATE_RECONNECT) {
            state = ReconnectState.STATE_CONNECTION_DELAY;
        }
        MyLog.iLog("reconnect state = " + state);
        switch (state) {
            case ReconnectState.STATE_BLUETOOTH_ON:
            case ReconnectState.STATE_SCAN_AUTO:
                ScanCycle(100);
                break;
            case ReconnectState.STATE_APP_ON:
                ScanCycle(2000);
                break;
            case ReconnectState.STATE_SCAN:
                ScanCycle(200);
                break;
            case ReconnectState.STATE_PERMISSION:
                ScanCycle(500);
                break;
            case ReconnectState.STATE_RECONNECT:
                CacheConnectCycle(100);
                break;
            case ReconnectState.STATE_NEW_GATT:
                AddressConnectCycle(100);
                break;
            case ReconnectState.STATE_SCAN_AGAIN:
                ScanAgain(500);
                break;
            case ReconnectState.STATE_CONNECTION_DELAY:
                CacheConnectCycle(ConstantsLibrary.TIME_SECONDS_DISCONNECT * 1000);
                break;
            default:
                break;
        }
    }

    /**
     * 执行搜索重连的周期机制
     */
    private void ScanCycle(long initialDelay) {
        stopReconnect();
        mDisposable = Observable.interval(initialDelay, TIME_INTERVAL_RECONNECT, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .map(aLong -> {
                    try {
                        MyLog.i("ScanCycle count = " + aLong);
                        PocDevice device = RepositoryDevice.getInstance(BApplication.getContext()).getLatestDeviceIoThread();
                        if (device != null && device.isBoundButDisConnect()) {
//                            MyLog.i("ScanCycle 发现断开连接的设备");
                            return device;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return null;
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::reconnectViaScan, throwable -> stopReconnect());
    }

    /**
     * 尝试使用 GATT 缓存进行连接
     * 尝试进行 3次连接 连接失败进行搜索重新连接
     * 当短暂连接是否可用
     */
    private void CacheConnectCycle(long initialDelay) {
        stopReconnect();
        mDisposable = Observable.intervalRange(1, 5, initialDelay, TIME_INTERVAL_RECONNECT_GATT, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .map(aLong -> {
                    try {
                        MyLog.i("CacheConnectCycle " + aLong);
                        if (aLong <= 3) {
                            PocDevice device = RepositoryDevice.getInstance(BApplication.getContext()).getLatestDeviceIoThread();
                            if (device != null && device.isBoundButDisConnect()) {
//                                MyLog.i("CacheConnectCycle 发现断开连接的设备");
                                return device;
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return null;
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::reconnectViaCache, throwable -> {
                    MyLog.e(throwable.getMessage());
                    reconnect(ReconnectState.STATE_NEW_GATT);
                });
    }


    /**
     * 执行搜索重连的周期机制
     */
    private void AddressConnectCycle(long initialDelay) {
        stopReconnect();
        mDisposable = Observable.interval(initialDelay, TIME_INTERVAL_RECONNECT_GATT, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .map(aLong -> {
                    try {
                        MyLog.i("AddressConnectCycle " + aLong);
                        PocDevice device = RepositoryDevice.getInstance(BApplication.getContext()).getLatestDeviceIoThread();
                        if (device != null && device.isBoundButDisConnect()) {
//                            MyLog.i("AddressConnectCycle 发现断开连接的设备");
                            return device;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return null;
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::reconnectViaNew, throwable -> reconnect(ReconnectState.STATE_SCAN_AUTO));
    }


    /**
     * 执行发射搜索
     */
    private void ScanAgain(long initialDelay) {
        stopReconnect();
        mDisposable = Observable.timer(initialDelay, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(aLong -> reconnectViaScan(null), throwable -> stopReconnect());
    }

}
