package com.eveningoutpost.dexdrip;

import android.app.Fragment;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.databinding.DataBindingUtil;
import android.graphics.Point;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.eveningoutpost.dexdrip.G5Model.Extensions;
import com.eveningoutpost.dexdrip.G5Model.Transmitter;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Dex_Constants;
import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.Calibration;
import com.eveningoutpost.dexdrip.Models.JoH;
import com.eveningoutpost.dexdrip.Models.Sensor;
import com.eveningoutpost.dexdrip.Models.TransmitterData;
import com.eveningoutpost.dexdrip.Models.UserError;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import com.eveningoutpost.dexdrip.Services.DexCollectionService;
import com.eveningoutpost.dexdrip.Services.G5CollectionService;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.SensorStatus;
import com.eveningoutpost.dexdrip.databinding.ActivitySystemStatusBinding;
import com.eveningoutpost.dexdrip.ui.MicroStatus;
import com.eveningoutpost.dexdrip.ui.MicroStatusImpl;
import com.eveningoutpost.dexdrip.utils.DexCollectionType;
import com.eveningoutpost.dexdrip.wearintegration.WatchUpdaterService;
import com.google.android.gms.wearable.DataMap;

import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Set;

import static com.eveningoutpost.dexdrip.Home.startWatchUpdaterService;
import static com.eveningoutpost.dexdrip.utils.DexCollectionType.DexcomG5;
import static com.eveningoutpost.dexdrip.xdrip.gs;

public class SystemStatusFragment extends Fragment {
    private static final int SMALL_SCREEN_WIDTH = 300;
    //public static final String menu_name = "System Status";
    private TextView version_name_view;
    private TextView collection_method;
    private TextView current_device;
    private TextView connection_status;
    private TextView sensor_status_view;
    private TextView transmitter_status_view;
    private TextView notes;
    private Button restart_collection_service;
    private Button forget_device;
    private Button futureDataDeleteButton;
    private ImageButton refresh;
    private SharedPreferences prefs;
    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    private ActiveBluetoothDevice activeBluetoothDevice;
    private static final String TAG = "SystemStatus";
    private BroadcastReceiver serviceDataReceiver;

    //@Inject
    MicroStatus microStatus;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        //Injectors.getMicroStatusComponent().inject(this);
        requestWearCollectorStatus();
        serviceDataReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context ctx, Intent intent) {
                final String action = intent.getAction();
                //final String msg = intent.getStringExtra("data");
                Bundle bundle = intent.getBundleExtra("data");
                if (bundle != null) {
                    DataMap dataMap = DataMap.fromBundle(bundle);
                    String lastState = dataMap.getString("lastState", "");
                    long last_timestamp = dataMap.getLong("timestamp", 0);
                    UserError.Log.d(TAG, "serviceDataReceiver onReceive:" + action + " :: " + lastState + " last_timestamp :: " + last_timestamp);
                    switch (action) {
                        case WatchUpdaterService.ACTION_BLUETOOTH_COLLECTION_SERVICE_UPDATE:
                            switch (DexCollectionType.getDexCollectionType()) {
                                case DexcomG5:
                                    G5CollectionService.setWatchStatus(dataMap);//msg, last_timestamp
                                    break;
                                case DexcomShare:
                                    if (lastState != null && !lastState.isEmpty()) {
                                        setConnectionStatus(lastState);//TODO getLastState() in non-G5 Services
                                    }
                                    break;
                                default:
                                    DexCollectionService.setWatchStatus(dataMap);//msg, last_timestamp
                                    if (lastState != null && !lastState.isEmpty()) {
                                        setConnectionStatus(lastState);
                                    }
                                    break;
                            }
                            break;
                    }
                }
            }
        };
        final ActivitySystemStatusBinding binding = DataBindingUtil.inflate(
                inflater, R.layout.activity_system_status, container, false);
        microStatus = new MicroStatusImpl();
        binding.setMs(microStatus);
        return binding.getRoot();
    }

    private void requestWearCollectorStatus() {
        final PowerManager.WakeLock wl = JoH.getWakeLock("ACTION_STATUS_COLLECTOR",120000);
        if (Home.get_enable_wear()) {
            if (DexCollectionType.getDexCollectionType().equals(DexcomG5)) {
                startWatchUpdaterService(safeGetContext(), WatchUpdaterService.ACTION_STATUS_COLLECTOR, TAG, "getBatteryStatusNow", G5CollectionService.getBatteryStatusNow);
            }
            else {
                startWatchUpdaterService(safeGetContext(), WatchUpdaterService.ACTION_STATUS_COLLECTOR, TAG);
            }
        }
        JoH.releaseWakeLock(wl);
    }

    @Override
    public void onPause() {
        if (serviceDataReceiver != null) {
            try {
                LocalBroadcastManager.getInstance(safeGetContext()).unregisterReceiver(serviceDataReceiver);
            } catch (IllegalArgumentException e) {
                UserError.Log.e(TAG, "broadcast receiver not registered", e);
            }
        }
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        final IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WatchUpdaterService.ACTION_BLUETOOTH_COLLECTION_SERVICE_UPDATE);
        LocalBroadcastManager.getInstance(safeGetContext()).registerReceiver(serviceDataReceiver, intentFilter);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // setContentView(R.layout.activity_system_status);
        // JoH.fixActionBar(this);
        prefs = PreferenceManager.getDefaultSharedPreferences(xdrip.getAppContext());
        final View v = getView();
        version_name_view = (TextView) v.findViewById(R.id.version_name);
        collection_method = (TextView) v.findViewById(R.id.collection_method);
        connection_status = (TextView) v.findViewById(R.id.connection_status);
        sensor_status_view = (TextView) v.findViewById(R.id.sensor_status);
        transmitter_status_view = (TextView) v.findViewById(R.id.transmitter_status);
        current_device = (TextView) v.findViewById(R.id.remembered_device);

        notes = (TextView) v.findViewById(R.id.other_notes);


        restart_collection_service = (Button) v.findViewById(R.id.restart_collection_service);
        forget_device = (Button) v.findViewById(R.id.forget_device);
        refresh = (ImageButton) v.findViewById(R.id.refresh_current_values);
        futureDataDeleteButton = (Button) v.findViewById(R.id.delete_future_data);

        //check for small devices:
        Display display = getActivity().getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int width = size.x;
        if (width < SMALL_SCREEN_WIDTH) {
            //adapt to small screen
            LinearLayout layout = (LinearLayout) v.findViewById(R.id.layout_collectionmethod);
            layout.setOrientation(LinearLayout.VERTICAL);
            layout = (LinearLayout) v.findViewById(R.id.layout_version);
            layout.setOrientation(LinearLayout.VERTICAL);
            layout = (LinearLayout) v.findViewById(R.id.layout_status);
            layout.setOrientation(LinearLayout.VERTICAL);
            layout = (LinearLayout) v.findViewById(R.id.layout_device);
            layout.setOrientation(LinearLayout.VERTICAL);
            layout = (LinearLayout) v.findViewById(R.id.layout_sensor);
            layout.setOrientation(LinearLayout.VERTICAL);
            layout = (LinearLayout) v.findViewById(R.id.layout_transmitter);
            layout.setOrientation(LinearLayout.VERTICAL);
        }

        set_current_values();
        restartButtonListener();
        forgetDeviceListener();
        refreshButtonListener();
    }

    //@Override
    //public String getMenuName() {
    //   return getString(R.string.system_status);
    //}

    private void set_current_values() {
        notes.setText("");
        activeBluetoothDevice = ActiveBluetoothDevice.first();
        if (Build.VERSION.SDK_INT >= 18) {
            mBluetoothManager = (BluetoothManager) safeGetContext().getSystemService(Context.BLUETOOTH_SERVICE);
        }
        setVersionName();
        //setCollectionMethod();
        setCurrentDevice();
        if (Home.get_follower()) {
            setConnectionStatusFollower();
        } else if (prefs.getString("dex_collection_method", "bogus").equals("WifiWixel")) {
            setConnectionStatusWifiWixel();
        } else {
            setConnectionStatus();
        }
        setSensorStatus();
        setTransmitterStatus();
        setNotes();
        futureDataCheck();

       /* if (notes.getText().length()==0) {
            notes.setText("Swipe for more status pages!");
        }*/
    }

    private void setTransmitterStatus() {

        if (prefs.getString("dex_collection_method", "BluetoothWixel").equals("DexcomShare")) {
            transmitter_status_view.setText("See Share Receiver");
            return;
        }

        TransmitterData td = TransmitterData.last();

        if (td == null || td.sensor_battery_level == 0) {
            transmitter_status_view.setText("not available");
            GcmActivity.requestSensorBatteryUpdate();
        } else if ((System.currentTimeMillis() - td.timestamp) > 1000 * 60 * 60 * 24) {
            transmitter_status_view.setText("no data in 24 hours");
            GcmActivity.requestSensorBatteryUpdate();
        } else {
            transmitter_status_view.setText("" + td.sensor_battery_level);
            GcmActivity.requestSensorBatteryUpdate(); // always ask
            if (td.sensor_battery_level <= Dex_Constants.TRANSMITTER_BATTERY_EMPTY) {
                transmitter_status_view.append(" - very low");
            } else if (td.sensor_battery_level <= Dex_Constants.TRANSMITTER_BATTERY_LOW) {
                transmitter_status_view.append(" - low");
                transmitter_status_view.append("\n(experimental interpretation)");
            } else {
                transmitter_status_view.append(" - ok");
            }
        }

    }


    private void setSensorStatus() {
        sensor_status_view.setText(SensorStatus.status());
    }


    private void setVersionName() {
        String versionName;
        try {
            versionName = safeGetContext().getPackageManager().getPackageInfo(safeGetContext().getPackageName(), PackageManager.GET_META_DATA).versionName;
            int versionNumber = safeGetContext().getPackageManager().getPackageInfo(safeGetContext().getPackageName(), PackageManager.GET_META_DATA).versionCode;
            versionName += "\nCode: " + BuildConfig.buildVersion + "\nDowngradable to: " + versionNumber;
            version_name_view.setText(versionName);
        } catch (PackageManager.NameNotFoundException e) {
            //e.printStackTrace();
            Log.e(this.getClass().getSimpleName(), "PackageManager.NameNotFoundException:" + e.getMessage());
        }
    }

    private void setCollectionMethod() {
        collection_method.setText(prefs.getString("dex_collection_method", "BluetoothWixel").replace("Dexbridge", "xBridge"));
    }

    public void setCurrentDevice() {
        if (activeBluetoothDevice != null) {
            current_device.setText(activeBluetoothDevice.name);
        } else {
            current_device.setText("None Set");
        }

        String collection_method = prefs.getString("dex_collection_method", "BluetoothWixel");
        if (collection_method.compareTo("DexcomG5") == 0) {
            Transmitter defaultTransmitter = new Transmitter(prefs.getString("dex_txid", "ABCDEF"));
            if (Build.VERSION.SDK_INT >= 18) {
                mBluetoothAdapter = mBluetoothManager.getAdapter();
            }
            if (mBluetoothAdapter != null) {
                Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
                if ((pairedDevices != null) && (pairedDevices.size() > 0)) {
                    for (BluetoothDevice device : pairedDevices) {
                        if (device.getName() != null) {

                            String transmitterIdLastTwo = Extensions.lastTwoCharactersOfString(defaultTransmitter.transmitterId);
                            String deviceNameLastTwo = Extensions.lastTwoCharactersOfString(device.getName());

                            if (transmitterIdLastTwo.equals(deviceNameLastTwo)) {
                                current_device.setText(defaultTransmitter.transmitterId);
                            }

                        }
                    }
                }
            } else {
                current_device.setText("No Bluetooth");
            }
        }
    }

    private void setConnectionStatusFollower() {
        if (GcmListenerSvc.lastMessageReceived == 0) {
            connection_status.setText(safeGetContext().getString(R.string.no_data));
        } else {
            connection_status.setText((JoH.qs((JoH.ts() - GcmListenerSvc.lastMessageReceived) / 60000, 0)) + " mins ago");
        }
    }

    private void setConnectionStatusWifiWixel() {
        if (ParakeetHelper.isParakeetCheckingIn()) {
            connection_status.setText(ParakeetHelper.parakeetStatusString());
        } else {
            connection_status.setText(safeGetContext().getString(R.string.no_data));
        }
    }

    public void setConnectionStatus(String msg) {
        if (msg != null && !msg.isEmpty()) {
            connection_status.setText(msg);
        }
    }

    private void setConnectionStatus() {
        boolean connected = false;
        if (mBluetoothManager != null && activeBluetoothDevice != null && (Build.VERSION.SDK_INT >= 18)) {
            for (BluetoothDevice bluetoothDevice : mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT)) {
                if (bluetoothDevice.getAddress().compareTo(activeBluetoothDevice.address) == 0) {
                    connected = true;
                }
            }
        }
        if (connected) {
            connection_status.setText(safeGetContext().getString(R.string.connected));
        } else {
            connection_status.setText(safeGetContext().getString(R.string.not_connected));
        }

        String collection_method = prefs.getString("dex_collection_method", "BluetoothWixel");
        if (collection_method.compareTo("DexcomG5") == 0) {
            Transmitter defaultTransmitter = new Transmitter(prefs.getString("dex_txid", "ABCDEF"));
            if (Build.VERSION.SDK_INT >= 18) mBluetoothAdapter = mBluetoothManager.getAdapter();
            if (mBluetoothAdapter != null) {
                Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
                if (pairedDevices.size() > 0) {
                    for (BluetoothDevice device : pairedDevices) {
                        if (device.getName() != null) {

                            String transmitterIdLastTwo = Extensions.lastTwoCharactersOfString(defaultTransmitter.transmitterId);
                            String deviceNameLastTwo = Extensions.lastTwoCharactersOfString(device.getName());

                            if (transmitterIdLastTwo.equals(deviceNameLastTwo)) {
                                final String fw = G5CollectionService.getFirmwareVersionString(defaultTransmitter.transmitterId);
                                connection_status.setText(device.getName() + " Authed" + ((fw != null) ? ("\n" + fw) : ""));
                                break;
                            }

                        }
                    }
                }
            } else {
                connection_status.setText(safeGetContext().getString(R.string.no_bluetooth)); 
            }
        }
    }

    private void setNotes() {
        try {

            if ((mBluetoothManager == null) || ((android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) && (mBluetoothManager.getAdapter() == null))) {
                notes.append("\n- This device does not seem to support bluetooth");
            } else {
                if ((android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
                        && !mBluetoothManager.getAdapter().isEnabled()) {
                    notes.append("\n- Bluetooth seems to be turned off");
                } else {
                    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        notes.append("\n- The android version of this device is not compatible with Bluetooth Low Energy");
                    }
                }
            }
        } catch (NullPointerException e) {
            Log.e(TAG, "Got nullpointer exception in setNotes ", e);
        }
    }

    private void futureDataCheck() {
        futureDataDeleteButton.setVisibility(View.GONE);
        final List<BgReading> futureReadings = BgReading.futureReadings();
        final List<Calibration> futureCalibrations = Calibration.futureCalibrations();
        if ((futureReadings != null && futureReadings.size() > 0) || (futureCalibrations != null && futureCalibrations.size() > 0)) {
            notes.append("\n- Your device has future data on it, Please double check the time and timezone on this phone.");
            futureDataDeleteButton.setVisibility(View.VISIBLE);
        }
        futureDataDeleteButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (futureReadings != null && futureReadings.size() > 0) {
                    for (BgReading bgReading : futureReadings) {
                        bgReading.calculated_value = 0;
                        bgReading.raw_data = 0;
                        bgReading.timestamp = 0;
                        bgReading.save();
                    }
                }
                if (futureCalibrations != null && futureCalibrations.size() > 0) {
                    for (Calibration calibration : futureCalibrations) {
                        calibration.slope_confidence = 0;
                        calibration.sensor_confidence = 0;
                        calibration.timestamp = 0;
                        calibration.save();
                    }
                }
            }
        });
    }

    private void restartButtonListener() {
        restart_collection_service.setOnClickListener(new View.OnClickListener() {
            public void onClick(final View v) {
                v.setEnabled(false);
                JoH.static_toast_short(gs(R.string.restarting_collector));
                v.setAlpha(0.2f);
                startWatchUpdaterService(safeGetContext(), WatchUpdaterService.ACTION_START_COLLECTOR, TAG);
                CollectionServiceStarter.restartCollectionService(safeGetContext());
                set_current_values();
                JoH.runOnUiThreadDelayed(new Runnable() {
                    @Override
                    public void run() {
                        v.setEnabled(true);
                        v.setAlpha(1.0f);
                        set_current_values();
                    }
                }, 2000);
            }
        });
    }

    private void forgetDeviceListener() {
        forget_device.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (mBluetoothManager != null && ActiveBluetoothDevice.first() != null) {
                    final BluetoothAdapter bluetoothAdapter = mBluetoothManager.getAdapter();
                    if (bluetoothAdapter != null) {
                        for (BluetoothDevice bluetoothDevice : bluetoothAdapter.getBondedDevices()) {
                            if (bluetoothDevice.getAddress().compareTo(ActiveBluetoothDevice.first().address) == 0) {
                                try {
                                    Method m = bluetoothDevice.getClass().getMethod("removeBond", (Class[]) null);
                                    m.invoke(bluetoothDevice, (Object[]) null);
                                    notes.append("\n- Bluetooth unbonded, if using share tell it to forget your device.");
                                    notes.append("\n- Scan for devices again to set connection back up!");
                                } catch (Exception e) {
                                    Log.e("SystemStatus", e.getMessage(), e);
                                }
                            }
                        }

                        ActiveBluetoothDevice.forget();
                        bluetoothAdapter.disable();


                        mHandler.postDelayed(new Runnable() {
                            public void run() {
                                bluetoothAdapter.enable();
                                set_current_values();
                                mHandler2.postDelayed(new Runnable() {
                                    public void run() {
                                        CollectionServiceStarter.restartCollectionService(safeGetContext());
                                        set_current_values();
                                    }
                                }, 5000);
                            }
                        }, 1000);
                    }
                }

                String collection_method = prefs.getString("dex_collection_method", "BluetoothWixel");
                if (collection_method.compareTo("DexcomG5") == 0) {
                    Transmitter defaultTransmitter = new Transmitter(prefs.getString("dex_txid", "ABCDEF"));
                    mBluetoothAdapter = mBluetoothManager.getAdapter();

                    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
                    if ((pairedDevices != null) && (pairedDevices.size() > 0)) {
                        for (BluetoothDevice device : pairedDevices) {
                            if (device.getName() != null) {

                                String transmitterIdLastTwo = Extensions.lastTwoCharactersOfString(defaultTransmitter.transmitterId);
                                String deviceNameLastTwo = Extensions.lastTwoCharactersOfString(device.getName());

                                if (transmitterIdLastTwo.equals(deviceNameLastTwo)) {
                                    try {
                                        Method m = device.getClass().getMethod("removeBond", (Class[]) null);
                                        m.invoke(device, (Object[]) null);
                                        notes.append("\nG5 Transmitter unbonded, switch device mode to prevent re-pairing to G5.");
                                    } catch (Exception e) {
                                        Log.e("SystemStatus", e.getMessage(), e);
                                    }
                                }

                            }
                        }
                    }
                }
            }
        });
    }

    private void refreshButtonListener() {
        refresh.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                set_current_values();
                requestWearCollectorStatus();
            }
        });
    }

    private Handler mHandler = new Handler();
    private Handler mHandler2 = new Handler();

    private Context safeGetContext() {
        if (isAdded()) {
            return getActivity();
        } else {
            return xdrip.getAppContext();
        }
    }

}