package io.kiotplugins.relaycontrol;

import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RelayControl extends CordovaPlugin {
    
    private static final String TAG = "RelayControl";
    private ExecutorService executor;
    private int maxRelayCount = 0;
    
    // Load the native library
    static {
        System.loadLibrary("relaycontrol");
    }
    
    // Native method declarations
    private native int getRelayCountNative();
    private native boolean setRelayStateNative(int relayNumber, int state);
    private native int getRelayStateNative(int relayNumber);
    private native boolean setModeNative(int mode);
    private native int getModeNative();
    private native boolean checkRelayAccessNative();
    private native boolean fixPermissionsNative();
    
    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);
        executor = Executors.newFixedThreadPool(2);
        
        // Check relay system access
        if (!checkRelayAccessNative()) {
            android.util.Log.w(TAG, "Relay system not accessible - attempting to fix permissions");
            
            // Try to fix permissions automatically
            if (fixPermissionsNative()) {
                android.util.Log.i(TAG, "Successfully fixed relay permissions");
                
                // Recheck access after fixing permissions
                if (checkRelayAccessNative()) {
                    android.util.Log.i(TAG, "Relay system now accessible after permission fix");
                } else {
                    android.util.Log.e(TAG, "Relay system still not accessible after permission fix");
                }
            } else {
                android.util.Log.e(TAG, "Failed to fix relay permissions - device may not be rooted");
            }
        }
        
        // Get relay count from native code
        maxRelayCount = getRelayCountNative();
        android.util.Log.i(TAG, "Initialized with " + maxRelayCount + " relays");
    }
    
    @Override
    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
        
        if ("turnOn".equals(action)) {
            int relayNumber = args.getInt(0);
            turnOnRelay(relayNumber, callbackContext);
            return true;
        }
        
        if ("turnOff".equals(action)) {
            int relayNumber = args.getInt(0);
            turnOffRelay(relayNumber, callbackContext);
            return true;
        }
        
        if ("setRelay".equals(action)) {
            int relayNumber = args.getInt(0);
            int state = args.getInt(1);
            setRelayState(relayNumber, state, callbackContext);
            return true;
        }
        
        if ("getStatus".equals(action)) {
            getRelayStatus(callbackContext);
            return true;
        }
        
        if ("getMode".equals(action)) {
            getMode(callbackContext);
            return true;
        }
        
        if ("setMode".equals(action)) {
            int mode = args.getInt(0);
            setMode(mode, callbackContext);
            return true;
        }
        
        if ("getRelayCount".equals(action)) {
            getRelayCount(callbackContext);
            return true;
        }
        
        if ("checkAccess".equals(action)) {
            checkAccess(callbackContext);
            return true;
        }
        
        if ("fixPermissions".equals(action)) {
            fixPermissions(callbackContext);
            return true;
        }
        
        return false;
    }
    
    private void turnOnRelay(int relayNumber, CallbackContext callbackContext) {
        setRelayState(relayNumber, 1, callbackContext);
    }
    
    private void turnOffRelay(int relayNumber, CallbackContext callbackContext) {
        setRelayState(relayNumber, 0, callbackContext);
    }
    
    private void setRelayState(int relayNumber, int state, CallbackContext callbackContext) {
        executor.execute(() -> {
            try {
                // Validate relay number
                if (relayNumber < 1 || relayNumber > maxRelayCount) {
                    callbackContext.error("Invalid relay number: " + relayNumber + ". Available relays: 1-" + maxRelayCount);
                    return;
                }
                
                // Use native method to set relay state
                boolean success = setRelayStateNative(relayNumber, state);
                
                if (success) {
                    // Verify the state was set correctly by reading it back
                    int currentState = getRelayStateNative(relayNumber);
                    if (currentState == state) {
                        JSONObject result = new JSONObject();
                        result.put("relay", relayNumber);
                        result.put("state", state);
                        result.put("success", true);
                        callbackContext.success(result);
                    } else {
                        callbackContext.error("Failed to verify relay " + relayNumber + " state. Expected: " + state + ", Got: " + currentState);
                    }
                } else {
                    callbackContext.error("Failed to set relay " + relayNumber + " to state " + state);
                }
                
            } catch (Exception e) {
                callbackContext.error("Error setting relay state: " + e.getMessage());
            }
        });
    }
    
    private void getRelayStatus(CallbackContext callbackContext) {
        executor.execute(() -> {
            try {
                JSONObject status = new JSONObject();
                
                // Get status for all relays
                for (int i = 1; i <= maxRelayCount; i++) {
                    int relayState = getRelayStateNative(i);
                    if (relayState >= 0) {
                        status.put("relay" + i, relayState);
                    } else {
                        android.util.Log.w(TAG, "Failed to read relay" + i + " state");
                    }
                }
                
                // Get mode
                int mode = getModeNative();
                if (mode >= 0) {
                    status.put("mode", mode);
                } else {
                    android.util.Log.w(TAG, "Failed to read mode");
                }
                
                status.put("timestamp", System.currentTimeMillis());
                status.put("relayCount", maxRelayCount);
                
                callbackContext.success(status);
                
            } catch (Exception e) {
                callbackContext.error("Error reading relay status: " + e.getMessage());
            }
        });
    }
    
    private void getMode(CallbackContext callbackContext) {
        executor.execute(() -> {
            try {
                int mode = getModeNative();
                if (mode >= 0) {
                    JSONObject result = new JSONObject();
                    result.put("mode", mode);
                    result.put("success", true);
                    callbackContext.success(result);
                } else {
                    callbackContext.error("Failed to read mode");
                }
            } catch (Exception e) {
                callbackContext.error("Error reading mode: " + e.getMessage());
            }
        });
    }
    
    private void setMode(int mode, CallbackContext callbackContext) {
        executor.execute(() -> {
            try {
                boolean success = setModeNative(mode);
                
                if (success) {
                    // Verify the mode was set correctly
                    int currentMode = getModeNative();
                    if (currentMode == mode) {
                        JSONObject result = new JSONObject();
                        result.put("mode", mode);
                        result.put("success", true);
                        callbackContext.success(result);
                    } else {
                        callbackContext.error("Failed to verify mode. Expected: " + mode + ", Got: " + currentMode);
                    }
                } else {
                    callbackContext.error("Failed to set mode to " + mode);
                }
                
            } catch (Exception e) {
                callbackContext.error("Error setting mode: " + e.getMessage());
            }
        });
    }
    
    private void getRelayCount(CallbackContext callbackContext) {
        try {
            JSONObject result = new JSONObject();
            result.put("count", maxRelayCount);
            result.put("success", true);
            callbackContext.success(result);
        } catch (JSONException e) {
            callbackContext.error("Error getting relay count: " + e.getMessage());
        }
    }
    
    private void checkAccess(CallbackContext callbackContext) {
        try {
            boolean hasAccess = checkRelayAccessNative();
            JSONObject result = new JSONObject();
            result.put("hasAccess", hasAccess);
            result.put("relayCount", maxRelayCount);
            result.put("success", true);
            callbackContext.success(result);
        } catch (JSONException e) {
            callbackContext.error("Error checking access: " + e.getMessage());
        }
    }
    
    private void fixPermissions(CallbackContext callbackContext) {
        executor.execute(() -> {
            try {
                boolean fixed = fixPermissionsNative();
                JSONObject result = new JSONObject();
                result.put("permissionsFixed", fixed);
                result.put("success", true);
                
                if (fixed) {
                    // Update relay count after fixing permissions
                    maxRelayCount = getRelayCountNative();
                    result.put("relayCount", maxRelayCount);
                    result.put("hasAccess", checkRelayAccessNative());
                    callbackContext.success(result);
                } else {
                    result.put("message", "Failed to fix permissions - device may not be rooted or su not available");
                    callbackContext.success(result);
                }
            } catch (Exception e) {
                callbackContext.error("Error fixing permissions: " + e.getMessage());
            }
        });
    }
    
    @Override
    public void onDestroy() {
        if (executor != null && !executor.isShutdown()) {
            executor.shutdown();
        }
        super.onDestroy();
    }
}