package com.app.simplitend.patient_dashboard;

import static com.app.simplitend.apputils.AppUtil.NOTIFICATION_ACTION;
import static com.app.simplitend.apputils.NotificationService.CONTENT_TYPE_KEY;
import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;

import android.Manifest;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.telecom.TelecomManager;
import android.util.Log;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.lifecycle.ViewModelProvider;

import com.app.simplitend.BuildConfig;
import com.app.simplitend.R;
import com.app.simplitend.apputils.AppUtil;
import com.app.simplitend.apputils.Constants;
import com.app.simplitend.apputils.PatientDataCache;
import com.app.simplitend.caregiverdashboard.mvvm.CgHomeContracts;
import com.app.simplitend.caregiverdashboard.mvvm.models.GeoFenceDetails;
import com.app.simplitend.patient_dashboard.foodreminders.FoodScheduler;

import io.socket.client.IO;
import io.socket.client.Socket;

public class DashBoardActivity extends AppCompatActivity implements CgHomeContracts.GetGeoFenceCallback {

    private static final String TAG = "DashBoardActivity_SOCKET";

    public static final String FOOD_REMINDERS = "food_reminders";

    protected PatientMainViewModel viewModel;

    protected ActivityResultLauncher<String> finePermissionLauncher;

    private Socket mSocket;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dash_board_cp);

        viewModel = new ViewModelProvider(this).get(PatientMainViewModel.class);

        FoodScheduler.scheduleFoodReminders(this);

        updateGeofenceDetails();

        finePermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(),
                isGranted -> {
                    if (isGranted) {
                        // getting location updates
                        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                            return;
                        }

                        viewModel.addLocationUpdates(this);
                    } else {
                        // permission denied
                        AppUtil.showAlert(this,
                                "We understand your privacy",
                                "To connect you with your guardian allow SimpliTend to access your location",
                                "Allow",
                                ((dialogInterface, i) -> {
                                    finePermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION);
                                }), null, null);
                    }

                });

        registerForActivityResult(new ActivityResultContracts.RequestPermission(),
                result -> {

                    // reigstering geofencing
                    // thus, asking for permission
                    finePermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION);

                    if (result) {
                        // permission granted
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            RoleManager roleManager = getSystemService(RoleManager.class);
                            Intent i = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING);
                            startActivityForResult(i, 1214, null);
                        }else{
                            requestPermissions(new String[]{Manifest.permission.CALL_PHONE, Manifest.permission.READ_PHONE_STATE, Manifest.permission.ANSWER_PHONE_CALLS}, 1212);
                        }
                    }
                }).launch(Manifest.permission.READ_CONTACTS);

        PatientDataCache.getPatientData(this, patientData -> {
            if (patientData == null) return;

            String uniqueKey = patientData.caregiver_iamprincipal_id + "medActivity" + patientData.id;
            initSocket(uniqueKey);
        }, false);
    }

    @Override
    protected void attachBaseContext(Context newBase) {
        final Configuration configuration = new Configuration(newBase.getResources().getConfiguration());
        configuration.fontScale = Math.min(configuration.fontScale, 1.1f);
        applyOverrideConfiguration(configuration);
        super.attachBaseContext(newBase);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mSocket != null) {
            mSocket.disconnect();
        }

        PatientMainViewModel.activityList = null;
        PatientMainViewModel.remindersList = null;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Log.d(TAG, "onActivityResult: " + resultCode);
    }

    private void initSocket(String uniqueKey) {
        if (mSocket != null) return;

        try {
            IO.Options options = new IO.Options();
            options.forceNew = true;
            options.reconnection = true;
            mSocket = IO.socket(BuildConfig.SIMPLITEND_SOKCET_HOST, options);

            mSocket.on(uniqueKey, args -> {
                try {
                    if (args.length >= 1) {
                        String content_type = (String) args[0];
                        Log.d(TAG, "call: " + content_type);
                        Intent broadcastIntent = new Intent(NOTIFICATION_ACTION);
                        if ("0".equals(content_type)) {
                            // medications
                            PatientMainViewModel.remindersList = null;
                            broadcastIntent.putExtra(CONTENT_TYPE_KEY, Constants.MEDICINE_TIME);
                        } else if ("1".equals(content_type)) {
                            // activities
                            PatientMainViewModel.activityList = null;
                            broadcastIntent.putExtra(CONTENT_TYPE_KEY, Constants.ACTIVITY_TIME);
                        }

                        sendBroadcast(broadcastIntent);
                    }
                } catch (Exception e) {
                    // do nothing
                    Log.d(TAG, "initializeSocket: ");
                }
            });

            mSocket.on(Socket.EVENT_CONNECT, args -> {
                Log.d(TAG, "Socket connected ");
            });

            mSocket.on(Socket.EVENT_DISCONNECT, args -> {
                Log.d(TAG, "Socket disconnected ");
            });

            mSocket.on(Socket.EVENT_CONNECT_ERROR, args -> {
                Exception e = (Exception) args[0];
                Log.e(TAG, "call: ", e);
            });

            mSocket.connect();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "SocketHelper: ", e);
        }
    }

    // saves the geofence details
    private void updateGeofenceDetails() {
        // retrieving geofence
        viewModel.getGeoFenceDetails(AppUtil.getPatientUid(this) + "",
                "", "Bearer " + AppUtil.getPatientToken(this),
                this);
    }

    public void validateAndAddGeofence(GeoFenceDetails geoFenceDetails) {
        if (geoFenceDetails.radius != null && geoFenceDetails.type != null) {
            PatientDataCache.getPatientData(this, (patientData -> {
                if (patientData != null) {
                    if (AppUtil.shouldAddPatientGeofence(this,
                            geoFenceDetails.radius, geoFenceDetails.type, patientData)) {
                        // should add a geofence
                        AppUtil.updatePatientGeofence(this, patientData.lat, patientData.lng,
                                geoFenceDetails.radius, geoFenceDetails.type, geoFenceDetails.message);
                    } else {
                        Log.d(GEOFENCE_TAG, "onGeofenceDetailsFetched: GEOFENCE DATA UP TO DATE");
                    }
                }
            }), false);
        }

    }

    @Override
    public void onGeofenceDetailsFetched(@NonNull GeoFenceDetails geoFenceDetails) {
        validateAndAddGeofence(geoFenceDetails);
    }

    @Override
    public void onGeofenceDetailsFetchFailed(Throwable throwable, String message) {
        Log.d(GEOFENCE_TAG, "onGeofenceDetailsFetchFailed: " + message);

    }
}