package com.cloudflare.realtimekit;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;
import android.view.WindowManager;

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import java.io.Serializable;
import java.util.HashMap;

import com.cloudflare.realtimekit.RTKHolder;

/*
 * RTKHelper here was renamed from RTKHelperModule to match the module name returned from getName()
 * Keeping different namings in React Module definition & getName() breaks in Expo with newArchitecture enabled
*/
@ReactModule(name = "RTKHelper")
public class RTKHelperModule extends ReactContextBaseJavaModule {

    private static final String TAG = "RTKHelperModule";
    private final ReactApplicationContext reactContext;
    private static final String ERROR_INVALID_ACTIVITY = "E_INVALID_ACTIVITY";

    // react-native-background-timer start
    private Handler handler;
    private ReactContext reactContext2;
    private Runnable runnable;
    private PowerManager powerManager;
    private PowerManager.WakeLock wakeLock;
    private int existingOrientation;
    private boolean isForcedLandscapeToggled;
    private final LifecycleEventListener listener = new LifecycleEventListener() {
        @Override
        public void onHostResume() {
        }

        @Override
        public void onHostPause() {
        }

        @Override
        public void onHostDestroy() {
            if (wakeLock.isHeld())
                wakeLock.release();
            // MediaProjectionService is owned by react-native-webrtc and stops itself
            // via MediaProjection.Callback.onStop() — no explicit stop needed here.
        }
    };
    // react-native-background-timer end

    private class Request {

        public boolean[] rationaleStatuses;
        public Callback callback;

        public Request(boolean[] rationaleStatuses, Callback callback) {
            this.rationaleStatuses = rationaleStatuses;
            this.callback = callback;
        }
    }

    public RTKHelperModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        this.powerManager = (PowerManager) getReactApplicationContext().getSystemService(reactContext.POWER_SERVICE);
        this.wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "realtimekit:wakelock");
        reactContext.addLifecycleEventListener(listener);
    }

    @Override
    public String getName() {
        return "RTKHelper";
    }

    @ReactMethod
    public void activateScreenWake() {
        final Activity activity = getCurrentActivity();

        if (activity != null) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                }
            });
        }
    }

    @ReactMethod
    public void deactivateScreenWake() {
        final Activity activity = getCurrentActivity();

        if (activity != null) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
                }
            });
        }
    }

    @ReactMethod
    public void forceLandscape() {
        final Activity activity = getCurrentActivity();

        if (activity != null) {
            this.isForcedLandscapeToggled = true;
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    existingOrientation = activity.getRequestedOrientation();
                    activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                }
            });
        }
    }

    @ReactMethod
    public void forcePotrait() {
        final Activity activity = getCurrentActivity();

        if (activity != null) {
            this.isForcedLandscapeToggled = true;
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    existingOrientation = activity.getRequestedOrientation();
                    activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                }
            });
        }
    }

    @ReactMethod
    public void resetOrientation() {
        final Activity activity = getCurrentActivity();

        if (activity != null) {
            this.isForcedLandscapeToggled = false;
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    activity.setRequestedOrientation(existingOrientation);
                }
            });
        }
    }

    @ReactMethod
    public void isForcedLandscape(Promise p) {
        p.resolve(this.isForcedLandscapeToggled);
    }

    @ReactMethod
    public void backgroundTimerStart(final int delay) {
        if (!wakeLock.isHeld())
            wakeLock.acquire();

        handler = new Handler();
        runnable = new Runnable() {
            @Override
            public void run() {
                backgroundTimerSendEvent(reactContext, "backgroundTimer");
            }
        };

        handler.post(runnable);
    }

    @ReactMethod
    public void backgroundTimerStop() {
        if (wakeLock.isHeld())
            wakeLock.release();

        // avoid null pointer exceptio when stop is called without start
        if (handler != null)
            handler.removeCallbacks(runnable);
    }

    private void backgroundTimerSendEvent(ReactContext reactContext, String eventName) {
        reactContext
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit(eventName, null);
    }

    @ReactMethod
    public void startMeetingService(ReadableMap config, Promise promise) {
        ReactApplicationContext context = getReactApplicationContext();
        String title       = config.hasKey("title")       ? config.getString("title")       : null;
        String text        = config.hasKey("text")        ? config.getString("text")        : null;
        String channelId   = config.hasKey("channelId")   ? config.getString("channelId")   : null;
        String channelName = config.hasKey("channelName") ? config.getString("channelName") : null;
        try {
            KeepAliveService.launch(context, title, text, channelId, channelName);
            promise.resolve(null);
        } catch (RuntimeException e) {
            // ForegroundServiceStartNotAllowedException or similar — not fatal.
            Log.w(TAG, "startMeetingService failed: " + e.getMessage());
            promise.resolve(null); // best-effort, never reject
        }
    }

    @ReactMethod
    public void stopMeetingService(Promise promise) {
        KeepAliveService.stop(getReactApplicationContext());
        promise.resolve(null);
    }

    @ReactMethod
    public void backgroundTimerSetTimeout(final int id, final double timeout) {
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (getReactApplicationContext().hasActiveCatalystInstance()) {
                    getReactApplicationContext()
                            .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                            .emit("backgroundTimer.timeout", id);
                }
            }
        }, (long) timeout);
    }
}
