/*
 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
 * All rights reserved.
 * Confidential and Proprietary - Qualcomm Technologies, Inc.
 */

package com.qualcomm.snapdragon.spaces.helpers;

import android.app.Activity;
import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.Display;
import android.widget.Toast;
import android.provider.Settings;
import java.lang.reflect.Method;

import com.qualcomm.qti.device.access.*;

public class LaunchHelper implements com.qualcomm.qti.device.access.DeviceAccessCallbacks
{
    private static final String TAG = "Spaces-LaunchHelper";

    private static final String _controllerActivity = "com.qualcomm.snapdragon.spaces.hostcontroller.ControllerActivity";

    private static LaunchHelper _instance;

    private Activity _callingActivity;

    private static boolean _hasCustomController = false;

    private static boolean _gameEngineIsFirstActivity = true;

    private DeviceAccessManager _deviceAccessMgr;

    private static LaunchHelper getInstance(Activity activity) {
        if (_instance == null) {
            _instance = new LaunchHelper(activity);
        } else {
            _instance._callingActivity = activity;
        }
        return _instance;
    }

    public LaunchHelper(Activity activity) {
        this(activity, true);
    }

    public LaunchHelper(Activity activity, boolean gameEngineIsFirstActivity) {
        _instance = this;
        _callingActivity = activity;
        _deviceAccessMgr = new DeviceAccessManager(this);
        _deviceAccessMgr.start(activity);
        _gameEngineIsFirstActivity = gameEngineIsFirstActivity;
        if (!getMetaDataFlag("SKIP_LAUNCH_ON_VIEWER")) {
            _hasCustomController = getMetaDataFlag("LAUNCH_CONTROLLER_ON_HOST");
        }
    }

    public boolean ShouldShowSplashScreen() {
        return getMetaDataFlag("SHOW_SPLASH_SCREEN_ON_HOST");
    }

    public boolean SkipPermissionCheck() {
        if (CanShowXRPermissions()) {
            Log.d(TAG, "Skipping permission checks in Spaces-LaunchHelper, because device supports XR permissions.");
            return true;
        }
        return getMetaDataFlag("SKIP_PERMISSION_CHECKS");
    }

    public static boolean CanShowXRPermissions() {
        // Only the Oppo MR devices can show XR permissions correctly at the moment.
        if (Build.MANUFACTURER.toLowerCase().equals("oppo") && Build.MODEL.toLowerCase().equals("ma01")) {
            return true;
        }
        try {
            Class<?> systemProperties = Class.forName("android.os.SystemProperties");
            Method getBoolean = systemProperties.getMethod("getBoolean", String.class, boolean.class);
            boolean isNativePopupSupport = (boolean) getBoolean.invoke(null, "spaces.native.popup.support", false);
            Log.d(TAG, "Is native popup support: " + isNativePopupSupport);
            if(isNativePopupSupport){
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return false;
    }

    public boolean StartGameEngineActivity() {
        return StartGameEngineActivity(getGameEngineActivity());
    }

    public boolean StartGameEngineActivity(String gameActivityName) {
        if( _deviceAccessMgr.bindDeviceAccess() ) {
            return startActivityOnGlassHelper(gameActivityName);
        } // else we start up in the callbacks of XRVD creation attempt, so no need to do anything
        Log.d(TAG, "failed to bindDeviceAccess....");
        return false;
    }

    public static boolean HasCustomController() {
        return _hasCustomController;
    }

    private String getGameEngineActivity() {
        /* This checks if we're running Unity, Unreal 4, or Unreal 5 Game Activity and picks accordingly */
        String mainGameActivity = "com.unity3d.player.UnityPlayerActivity";
        try {
            Class.forName(mainGameActivity);
            return mainGameActivity;
        } catch(ClassNotFoundException e) {
            //Log.v(TAG, "Main game activity name com.unity3d.player.UnityPlayerActivity is not available.");
        }

        mainGameActivity = "com.epicgames.ue4.GameActivity";
        try {
            Class.forName(mainGameActivity);
            return mainGameActivity;
        } catch(ClassNotFoundException e) {
            //Log.v(TAG, "Main game activity name com.epicgames.ue4.GameActivity is not available.");
        }

        mainGameActivity = "com.epicgames.unreal.GameActivity";
        try {
            Class.forName(mainGameActivity);
            return mainGameActivity;
        } catch(ClassNotFoundException e) {
            //Log.v(TAG, "Main game activity name com.epicgames.unreal.GameActivity is not available.");
        }

        Log.e(TAG, "No main game activity is available.");

        return mainGameActivity;
    }

    private boolean getMetaDataFlag(String key) {
        boolean flag = false;
        try {
            ApplicationInfo app = _callingActivity.getPackageManager().getApplicationInfo(_callingActivity.getPackageName(), PackageManager.GET_META_DATA);
            Bundle bundle = app.metaData;

            flag = bundle.getBoolean("com.qualcomm.snapdragon.spaces." + key, false);
        } catch (Exception e) {
            Log.e(TAG, "Can't get meta data info to retrieve flag for: " + key);
            e.printStackTrace();
        }

        return flag;
    }

    public boolean startActivityOnGlassHelper(String activityName) {
        Intent mainLaunchIntent = new Intent(_callingActivity.getIntent());
        Bundle startupBundle = null;

        Log.v(TAG, "Setting next activity to: " + activityName);
        mainLaunchIntent.setClassName(_callingActivity, activityName);
        mainLaunchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        mainLaunchIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);

        /*
         * (10/4/23): Since we only have support for 1 wired glasses by LENOVO at this time as well as the WirelessVD
         * display we need to default everything to starting up on display ID 0. Reason is for a casting or any other
         * detection of a display it will cause app to launch on that disply and the controller will default to the
         * main display.  For AIO use case, this means, casting or capture sink gets the app and VR headset gets the
         * controller.  So we are going to turn off controller and ONLY set displayID in a positive detection.  This
         * does mean that for future wired glasses this code will need to be updated to adjust if the glasses enumerate
         * as a secondary display.
         */
        _hasCustomController = false;
        Log.v(TAG, "Setting default screen ID of 0...");
        int id = 0;
        boolean launchOnViewer = !getMetaDataFlag("SKIP_LAUNCH_ON_VIEWER");
        if (launchOnViewer) {
            id = _deviceAccessMgr.getLaunchDisplayId(true);
        }

        if (id > 0) {
            Log.v(TAG, "Launching main activity to DisplayId: " + id);
            boolean showLaunchMessageOnHost = getMetaDataFlag("SHOW_LAUNCH_MESSAGE_ON_HOST");

            if (showLaunchMessageOnHost && !_hasCustomController) {
                Log.v(TAG, "Showing launch message on host.");
                Toast.makeText(_callingActivity, "Launching application on the Viewer!", Toast.LENGTH_LONG).show();
            }
        } else {
            if (launchOnViewer) {
                Log.e(TAG, "No Viewer device found to start application on!");
            } else {
                Log.v(TAG, "Skipped enumerating secondary displays because SKIP_LAUNCH_ON_VIEWER flag was set.");
            }
        }
        // Now re-check if we have a 2nd display and if we should launch controller
        if (id != 0 && !getMetaDataFlag("SKIP_LAUNCH_ON_VIEWER")) {
            _hasCustomController = getMetaDataFlag("LAUNCH_CONTROLLER_ON_HOST");
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startupBundle = ActivityOptions.makeBasic().setLaunchDisplayId(id).toBundle();
        }
        mainLaunchIntent.putExtras(startupBundle);

        _callingActivity.startActivityIfNeeded(mainLaunchIntent, 0, startupBundle);

        if(!_hasCustomController && !ShouldShowSplashScreen()) {
            _callingActivity.finishAffinity();
        }

        return true;
    }

    public static void tryStartControllerActivity(Activity activity) {
        if (_hasCustomController) {
            Intent controllerIntent = new Intent(activity.getIntent());
            Bundle startupBundle = null;
            controllerIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
            controllerIntent.setClassName(activity, _controllerActivity);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startupBundle = ActivityOptions.makeBasic().setLaunchDisplayId(0).toBundle();
            }
            controllerIntent.putExtras(startupBundle);

            activity.startActivity(controllerIntent, startupBundle);
        } else {
            Log.e(TAG, "There was no Spaces Controller included in the project! No controller to launch therefore.");
        }
    }

    @Override
    public void OnServiceReady() {
    }

    @Override
    public void OnServiceLost() {

    }
}
