package io.trustbuilder.mfa.android.demoapp.screen;

import android.Manifest;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import androidx.core.view.WindowCompat;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;

import com.google.firebase.BuildConfig;

import java.util.Map;
import java.util.Objects;
import java.util.Random;

import io.trustbuilder.mfa.android.demoapp.R;
import io.trustbuilder.mfa.android.demoapp.screen.selfcare.DeleteSecureTokenActivity;
import io.trustbuilder.mfa.android.demoapp.screen.selfcare.GetSecureTokensActivity;
import io.trustbuilder.mfa.android.demoapp.screen.selfcare.LockSecureTokenActivity;
import io.trustbuilder.mfa.android.demoapp.screen.selfcare.UnlockSecureTokenActivity;
import io.trustbuilder.mfa.android.demoapp.security.SecurityUtils;
import io.trustbuilder.mfa.android.demoapp.utils.FirebaseService;
import io.trustbuilder.mfa.android.demoapp.utils.FirebaseServiceFactory;
import io.trustbuilder.mfa.android.demoapp.utils.HasFirebaseServiceFactory;
import io.trustbuilder.mfa.android.demoapp.utils.PushNotificationReceiveService;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    protected TextView result;
    protected MutableLiveData<Map<String, String>> inAppMessage;
    protected MutableLiveData<String> fcmToken;
    private String fcmTokenValue;
    private Button secureToken;
    private Button enrollSecureToken;
    private Button getPendingAuthSessions;
    private Button deleteLocalSecureToken;
    private Button authentication;
    private Button authorize;
    private Button inAppAuthenticate;
    private Button cancelAuth;
    private Button resetSecretCode;
    private Button changeSecretCode;
    private Button registerPushId;
    private Button updateSecureTokenFriendlyName;
    private Button sealing;
    private Button activationCodeGeneration;
    private Button generateAndSendResetCode;
    private Button lockSecureToken;
    private Button unlockSecureToken;
    private Button deleteSecureToken;
    private Button getSecureTokens;
    private Button registerBiokey;

    private FirebaseService firebaseService;
    private FirebaseServiceFactory firebaseServiceFactory;

    @Override
    protected void onResume() {
        super.onResume();
        if (!BuildConfig.DEBUG && SecurityUtils.isDeviceRooted()) {
            SecurityUtils.showAlertDialogAndExitApp(this,
                     R.string.device_rooted_message);
        }
        askNotificationPermission();
        if (this.firebaseService != null) {
            this.firebaseService.fetchToken(new FirebaseService.FirebaseCallback() {
                @Override
                public void onTokenReceived(String token) {
                    Log.d(TAG, "FCM token: " + token);
                    fcmTokenValue = token;
                }

                @Override
                public void onError(Exception e) {
                    Log.e(TAG, "Firebase error", e);
                }
            });
        }
    }

    private void setupFCMTokenChangeObserver() {
        this.fcmToken = PushNotificationReceiveService.getNewToken();
        final Observer<String> tokenObserver = token -> {
            if (token != null) {
                Log.d(TAG, "setupFCMTokenChangeObserver: " + this.fcmToken + " " + token);
                fcmToken.postValue(null);
            }
        };
        fcmToken.observe(this, tokenObserver);
    }

    public void showNotification(Map<String, String> message) {
        NotificationManager mNotificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("DemoNativeChannelId",
                    "Demo Native Channel",
                    NotificationManager.IMPORTANCE_HIGH);
            channel.setDescription("Notification channel");
            mNotificationManager.createNotificationChannel(channel);
        }
        Intent intent;
        if(Objects.equals(message.get("scope"), "AUTH")) {
            intent = new Intent(getApplicationContext(), AuthenticationActivity.class);
        }
        else if (Objects.equals(message.get("scope"), "SEAL")) {
            intent = new Intent(getApplicationContext(), SealingActivity.class);
        }
        else {
            intent = new Intent(getApplicationContext(), MainActivity.class);
        }
        Bundle b = new Bundle();
        b.putString("tknAlias",message.get("tknAlias"));
        b.putString("authSessionId",message.get("authSessionId"));
        b.putString("cnxAlias",message.get("cnxAlias"));
        intent.putExtras(b);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, (int) (System.currentTimeMillis()/1000), intent, PendingIntent.FLAG_IMMUTABLE);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(), "DemoNativeChannelId")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(message.get("title"))
                .setContentText(message.get("body"))
                .setAutoCancel(true)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setContentIntent(pendingIntent);
        mNotificationManager.notify(new Random().nextInt(100), mBuilder.build());
        Log.d(TAG, "showNotification: Done");
    }

    private void setupInAppMessageObserver() {
        this.inAppMessage = PushNotificationReceiveService.getInAppMessage();
        final Observer<Map<String, String>> messageObserver = message -> {
            Log.d(TAG, "setupInAppMessageObserve: " + message);
            if (message != null) {
                result.setText(mapToFormattedString(message));
                showNotification(message);
                inAppMessage.postValue(null);
            }
        };
        inAppMessage.observe(this, messageObserver);
    }

    public static String mapToFormattedString(Map<String, String> map) {
        return map.entrySet().stream()
                .reduce("",
                        (acc, entry) -> acc + entry.getKey() + " : " + entry.getValue() + "\n",
                        String::concat);
    }

    private final ActivityResultLauncher<String> requestPermissionLauncher = registerForActivityResult(
            new ActivityResultContracts.RequestPermission(), isGranted -> {
                if (isGranted) {
                    Log.d(TAG, "Permission allow on launch");
                } else {
                    // TODO: Inform user that that your app will not show notifications.
                }
            });

    private void askNotificationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(this,
                    Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "Permission allow");
            } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
                // TODO: display an educational UI
            } else {
                requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
            }
        }
    }

    public void setFirebaseService(FirebaseService service) {
        this.firebaseService = service;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate: MainActivity");
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide();
        super.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
        setTitle("Demo Android");
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        setContentView(R.layout.activity_main);
        if (firebaseServiceFactory == null) {
            firebaseServiceFactory =
                    ((HasFirebaseServiceFactory) getApplication())
                            .getFirebaseServiceFactory();
        }
        firebaseService = firebaseServiceFactory.create();
        this.result = this.findViewById(R.id.NotifData);
        setupInAppMessageObserver();
        setupFCMTokenChangeObserver();
        this.secureToken = this.findViewById(R.id.SecureTokenListing);
        this.getPendingAuthSessions = this.findViewById(R.id.PendingAuthSessionsRetrieval);
        this.deleteLocalSecureToken = this.findViewById(R.id.DeleteLocalSecureToken);
        this.enrollSecureToken = this.findViewById(R.id.SecureTokenEnrollment);
        this.authentication = this.findViewById(R.id.Authentication);
        this.authorize = this.findViewById(R.id.AuthorizationRequest);
        this.inAppAuthenticate = this.findViewById(R.id.InAppAuthentication);
        this.cancelAuth = this.findViewById(R.id.AuthSessionCancellation);
        this.resetSecretCode = this.findViewById(R.id.SecretCodeReset);
        this.changeSecretCode = this.findViewById(R.id.SecretCodeChange);
        this.registerPushId = this.findViewById(R.id.PushIdRegistration);
        this.updateSecureTokenFriendlyName = this.findViewById(R.id.SecureTokenFriendlyNameUpdate);
        this.sealing = this.findViewById(R.id.Sealing);
        this.activationCodeGeneration = this.findViewById(R.id.ActivationCodeGeneration);
        this.generateAndSendResetCode = this.findViewById(R.id.ResetCodeGeneration);
        this.lockSecureToken = this.findViewById(R.id.LockSecureToken);
        this.unlockSecureToken = this.findViewById(R.id.UnlockSecureToken);
        this.deleteSecureToken = this.findViewById(R.id.DeleteSecureToken);
        this.getSecureTokens = this.findViewById(R.id.GetSecureTokens);
        this.registerBiokey = this.findViewById(R.id.RegisterBiokey);
    }

    public void setFirebaseServiceFactory(FirebaseServiceFactory factory) {
        this.firebaseServiceFactory = factory;
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart: MainActivity");
        this.secureToken.setOnClickListener((v) -> {
            startActivity(new Intent(this, SecureTokenListingActivity.class));
        });
        this.enrollSecureToken.setOnClickListener((v) -> {
            startActivity(new Intent(this, SecureTokenEnrollmentActivity.class));
        });
        this.getPendingAuthSessions.setOnClickListener((v) -> {
            startActivity(new Intent(this, PendingAuthSessionsRetrievalActivity.class));
        });
        this.deleteLocalSecureToken.setOnClickListener((v) -> {
            startActivity(new Intent(this, DeleteLocalSecureTokenActivity.class));
        });
        this.authentication.setOnClickListener((v) -> {
            startActivity(new Intent(this, AuthenticationActivity.class));
        });
        this.authorize.setOnClickListener((v) -> {
            startActivity(new Intent(this, AuthorizationRequestActivity.class));
        });
        this.inAppAuthenticate.setOnClickListener((v) -> {
            startActivity(new Intent(this, InAppAuthenticationActivity.class));
        });
        this.cancelAuth.setOnClickListener((v) -> {
            startActivity(new Intent(this, AuthSessionCancellationActivity.class));
        });
        this.resetSecretCode.setOnClickListener((v) -> {
            startActivity(new Intent(this, SecretCodeResetActivity.class));
        });
        this.changeSecretCode.setOnClickListener((v) -> {
            startActivity(new Intent(this, SecretCodeChangeActivity.class));
        });
        this.registerPushId.setOnClickListener((v) -> {
            Intent intent = new Intent(this, PushIdRegistrationActivity.class);
            intent.putExtra("FCM_TOKEN", fcmTokenValue);
            startActivity(intent);
        });
        this.updateSecureTokenFriendlyName.setOnClickListener((v) -> {
            startActivity(new Intent(this, SecureTokenFriendlyNameUpdateActivity.class));
        });
        this.sealing.setOnClickListener((v) -> {
            startActivity(new Intent(this, SealingActivity.class));
        });
        this.activationCodeGeneration.setOnClickListener((v) -> {
            startActivity(new Intent(this, ActivationCodeGenerationActivity.class));
        });
        this.generateAndSendResetCode.setOnClickListener((v) -> {
            startActivity(new Intent(this, ResetCodeGenerationActivity.class));
        });
        this.lockSecureToken.setOnClickListener((v) -> {
            startActivity(new Intent(this, LockSecureTokenActivity.class));
        });
        this.unlockSecureToken.setOnClickListener((v) -> {
            startActivity(new Intent(this, UnlockSecureTokenActivity.class));
        });
        this.deleteSecureToken.setOnClickListener((v) -> {
            startActivity(new Intent(this, DeleteSecureTokenActivity.class));
        });
        this.getSecureTokens.setOnClickListener((v) -> {
            startActivity(new Intent(this, GetSecureTokensActivity.class));
        });
        this.registerBiokey.setOnClickListener((v) -> {
            startActivity(new Intent(this, RegisterBiokeyActivity.class));
        });
    }
}