package com.foxx.androidcast.remoteaccess.control;

import org.json.JSONException;
import org.json.JSONObject;

import com.foxx.androidcast.remoteaccess.RemoteAccessMode;
import com.foxx.androidcast.remoteaccess.RemoteAccessVpnRouting;

/**
 * JSON schema for the RA control web UI — mirrors developer remote-access settings.
 * Apply logic runs in the main process via {@link RemoteAccessControlHostImpl}.
 */
public final class RemoteAccessControlPrefsMirror {
    public static final String KEY_MODE = "remote_access_mode";
    public static final String KEY_VPN_ROUTE_SCOPE = "vpn_route_scope";
    public static final String KEY_VPN_APP_SCOPE = "vpn_app_scope";
    public static final String KEY_SESSION_ID = "session_id";
    public static final String KEY_EXPIRES_AT = "expires_at_epoch_sec";

    private RemoteAccessControlPrefsMirror() {}

    public static JSONObject buildSnapshot(
            RemoteAccessMode mode,
            RemoteAccessVpnRouting.RouteScope routeScope,
            RemoteAccessVpnRouting.AppScope appScope,
            String sessionId,
            long expiresAtEpochSec) throws JSONException {
        JSONObject root = new JSONObject();
        root.put(KEY_MODE, mode != null ? mode.name() : RemoteAccessMode.DISABLED.name());
        root.put(KEY_VPN_ROUTE_SCOPE, routeScope != null ? routeScope.name()
                : RemoteAccessVpnRouting.RouteScope.HUB_ONLY.name());
        root.put(KEY_VPN_APP_SCOPE, appScope != null ? appScope.name()
                : RemoteAccessVpnRouting.AppScope.ALL_APPS.name());
        root.put(KEY_SESSION_ID, sessionId != null ? sessionId : "");
        root.put(KEY_EXPIRES_AT, expiresAtEpochSec);
        JSONObject options = new JSONObject();
        RemoteAccessMode[] modes = RemoteAccessMode.values();
        for (RemoteAccessMode m : modes) {
            options.put(m.name(), m.name());
        }
        root.put("mode_options", options);
        root.put("vpn_route_scope_options", enumNames(RemoteAccessVpnRouting.RouteScope.values()));
        root.put("vpn_app_scope_options", enumNames(RemoteAccessVpnRouting.AppScope.values()));
        return root;
    }

    public static ApplyResult parseApplyPatch(String bodyJson) {
        if (bodyJson == null || bodyJson.trim().isEmpty()) {
            return ApplyResult.error("empty body");
        }
        try {
            JSONObject body = new JSONObject(bodyJson);
            RemoteAccessMode mode = null;
            if (body.has(KEY_MODE)) {
                mode = RemoteAccessMode.fromStored(body.optString(KEY_MODE, ""));
            }
            RemoteAccessVpnRouting.RouteScope routeScope = null;
            if (body.has(KEY_VPN_ROUTE_SCOPE)) {
                routeScope = RemoteAccessVpnRouting.RouteScope.fromStored(
                        body.optString(KEY_VPN_ROUTE_SCOPE, ""));
            }
            RemoteAccessVpnRouting.AppScope appScope = null;
            if (body.has(KEY_VPN_APP_SCOPE)) {
                appScope = RemoteAccessVpnRouting.AppScope.fromStored(
                        body.optString(KEY_VPN_APP_SCOPE, ""));
            }
            return ApplyResult.ok(mode, routeScope, appScope);
        } catch (JSONException e) {
            return ApplyResult.error("invalid json: " + e.getMessage());
        }
    }

    public static JSONObject successResponse(JSONObject settings) throws JSONException {
        JSONObject out = new JSONObject();
        out.put("ok", true);
        out.put("settings", settings);
        return out;
    }

    public static JSONObject errorResponse(String message) throws JSONException {
        JSONObject out = new JSONObject();
        out.put("ok", false);
        out.put("error", message != null ? message : "error");
        return out;
    }

    private static JSONObject enumNames(Enum<?>[] values) throws JSONException {
        JSONObject out = new JSONObject();
        for (Enum<?> v : values) {
            out.put(v.name(), v.name());
        }
        return out;
    }

    public static final class ApplyResult {
        public final boolean ok;
        public final String error;
        public final RemoteAccessMode mode;
        public final RemoteAccessVpnRouting.RouteScope routeScope;
        public final RemoteAccessVpnRouting.AppScope appScope;

        private ApplyResult(
                boolean ok,
                String error,
                RemoteAccessMode mode,
                RemoteAccessVpnRouting.RouteScope routeScope,
                RemoteAccessVpnRouting.AppScope appScope) {
            this.ok = ok;
            this.error = error;
            this.mode = mode;
            this.routeScope = routeScope;
            this.appScope = appScope;
        }

        public static ApplyResult ok(
                RemoteAccessMode mode,
                RemoteAccessVpnRouting.RouteScope routeScope,
                RemoteAccessVpnRouting.AppScope appScope) {
            return new ApplyResult(true, null, mode, routeScope, appScope);
        }

        public static ApplyResult error(String message) {
            return new ApplyResult(false, message, null, null, null);
        }

        public boolean hasChanges() {
            return mode != null || routeScope != null || appScope != null;
        }
    }
}
