package com.pavle.patternswitch.bluetooth;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.util.Log;

import com.pavle.patternswitch.activities.PatternPreviewActivity;
import com.pavle.patternswitch.objects.Device;
import com.pavle.patternswitch.objects.Interaction;
import com.pavle.patternswitch.objects.Pattern;
import com.pavle.patternswitch.objects.Trigger;
import com.pavle.patternswitch.objects.TriggerCallback;

import java.util.List;

/**
 * Wraps the BleWrapper and adds functionality to handle triggers
 * Also acts like a personal WrapperCallback object
 */
public class BleWrapperProxy implements Runnable {

    private Trigger mTrigger;
    private BleWrapper mWrapper;
    private Context mParent;
    private List<Device> mDeviceList;


    private boolean mRevserse;
    private boolean isReversable;


    private int counterRssi;
    private int sum;
    private Pattern mPattern;
    private BleWrapperProxy mProxy;


    private int distance;

    public BleWrapperProxy(Context parent, Trigger t, List<Device> list,Pattern p) {
        mParent = parent;
        mWrapper = new BleWrapper(parent, new ProxyCallback());
        mWrapper.initialize();
        mWrapper.createHandler();
        mTrigger = t;
        distance = Math.abs(mTrigger.getDistance());
        mDeviceList = list;
        mPattern = p;
        mProxy = this;
    }

    @Override
    public void run() {
        if(mPattern.isChecked())
            while(!mWrapper.isConnected()){ //FIGURE OUT WHY THIS BLOCKS MAIN THREAD OF EXECUTION AND FIX IT
                try {
                    if (mTrigger.getDevice() == null){
                        for (Device d : mDeviceList) {
                            String name = d.getDevice().getName();
                            if (name.equals(mTrigger.getTriggerDeviceName())) {
                                mTrigger.setDevice(d);
                                mWrapper.connect(d.getDevice().getAddress());
                            }
                        }
                    } else{
                        ((PatternPreviewActivity) mParent).createHandler(mWrapper);
                        mWrapper.connect(mTrigger.getDevice().getDevice().getAddress());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    }

    public void setReverse(boolean reverse){
        if(isReversable)
            mRevserse = reverse;
    }
    public void setIsReversable(boolean reversable){
        isReversable = reversable;
    }

    public void stop() {
        mWrapper.stopMonitoringRssiValue();
        mWrapper.disconnect();
        mWrapper.close();
    }

    private class ProxyCallback implements BleWrapperCallbacks{

        @Override
        public void uiDeviceFound(BluetoothDevice device, int rssi, byte[] record) {

        }

        @Override
        public void uiDeviceConnected() {
            mWrapper.setRSSISamplingTime(100);
            mWrapper.startMonitoringRssiValue();
        }

        @Override
        public void uiDeviceDisconnected() {
            mWrapper.setRSSISamplingTime(500);
            mWrapper.stopMonitoringRssiValue();
            mProxy.run();
        }

        @Override
        public void uiAvailableServices(boolean success) {

        }

        @Override
        public void uiCharacteristicsForServices(boolean success) {

        }

        @Override
        public void uiNotificationsSet(boolean success) {

        }

        @Override
        public void uiNewRssiAvailable(BluetoothGatt gatt, BluetoothDevice device, int rssi) {
            if (counterRssi % 4 == 0 && counterRssi != 0) {
                sum /= 4;
                addNewValue(sum);
                sum = 0;
            }
            sum += Math.abs(rssi);
            counterRssi++;
        }
        private int oldValue;

        private void addNewValue(int newValue) {
            Log.e("BREAD","New Value: "+newValue+" Old Value: "+oldValue);


            if (oldValue == 0) {
                oldValue = newValue;
                return;
            }

            if ((mTrigger.getGoingTo() == Trigger.GOING_TO && !mRevserse) ||
                    (mTrigger.getGoingTo() == Trigger.COMING_FROM && mRevserse)) {
                if (newValue < distance && oldValue < distance && newValue < oldValue) {
                    Log.e("BREAD","Going To Activated");
                    runInteractions();
                }
            } else {
                if (newValue > distance && oldValue > distance && newValue > oldValue) {
                    Log.e("BREAD", "Coming From Activated");
                    runInteractions();
                }
            }
            oldValue = newValue;
        }

        private void runInteractions() {
            for (final Interaction i : mTrigger.getInteractionList()) {
                Log.e("BREAD", "New Interaction not run");
                Log.e("BREAD","Run Interactions");

                    TriggerCallback tc = new TriggerCallback();
                    try {
                        final BleWrapper tmp = new BleWrapper(mParent, tc);
                        tmp.initialize();

                        if ((i.getMethodFlags() == Interaction.FLAG_OFF && !mRevserse)||
                                (i.getMethodFlags() == Interaction.FLAG_ON && mRevserse)) {
                            tc.setOn(false, tmp, mParent, mTrigger, mWrapper, BleWrapperProxy.this);
                            Log.e("BREAD", "Interaction Off");
                        } else {
                            tc.setOn(true, tmp, mParent, mTrigger, mWrapper, BleWrapperProxy.this);
                            Log.e("BREAD", "Interaction On");
                        }
                        ((PatternPreviewActivity) mParent).runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                tmp.connect(i.getDevice().getDevice().getAddress());
                            }
                        });
                    } catch (Exception e) {
                        Log.e("BREAD", "Exception "+e.getMessage());
                        e.printStackTrace();
                    }
            }
        }


        @Override
        public void uiNewValueForCharacteristic(BluetoothGatt gatt, BluetoothDevice device, BluetoothGattService service, BluetoothGattCharacteristic ch, String strValue, int intValue, byte[] rawValue, String timestamp) {

        }

        @Override
        public void uiGotNotification(BluetoothGatt gatt, BluetoothDevice device, BluetoothGattService service, BluetoothGattCharacteristic characteristic) {

        }

        @Override
        public void uiSuccessfulWrite(BluetoothGatt gatt, BluetoothDevice device, BluetoothGattService service, BluetoothGattCharacteristic ch, String description) {

        }

        @Override
        public void uiFailedWrite(BluetoothGatt gatt, BluetoothDevice device, BluetoothGattService service, BluetoothGattCharacteristic ch, String description) {

        }
    }
}
