package com.foxx.androidcast.vpn;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.net.VpnService;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.util.Log;

import com.foxx.androidcast.CastTrayNotifier;
import com.foxx.androidcast.remoteaccess.WireGuardQuickConfig;

import java.net.InetAddress;

/** TUN fallback when GoBackend cannot start — runs in :vpn process only. */
public final class RemoteAccessVpnService extends VpnService {
    private static final String TAG = "RemoteAccessVPN";
    public static final String ACTION_UP = "com.foxx.androidcast.vpn.VPN_UP";
    public static final String ACTION_DOWN = "com.foxx.androidcast.vpn.VPN_DOWN";
    public static final String EXTRA_WG_CONFIG = "wg_config";

    private ParcelFileDescriptor tun;

    public static boolean startWithConfig(Context context, String wgConfig) {
        Intent prep = VpnService.prepare(context);
        if (prep != null) {
            Log.w(TAG, "VPN permission not granted");
            return false;
        }
        Intent i = new Intent(context, RemoteAccessVpnService.class);
        i.setAction(ACTION_UP);
        i.putExtra(EXTRA_WG_CONFIG, wgConfig);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(i);
        } else {
            context.startService(i);
        }
        return true;
    }

    public static void stop(Context context) {
        Intent i = new Intent(context, RemoteAccessVpnService.class);
        i.setAction(ACTION_DOWN);
        context.startService(i);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String action = intent != null ? intent.getAction() : null;
        if (ACTION_DOWN.equals(action)) {
            tearDown();
            stopForeground(STOP_FOREGROUND_REMOVE);
            stopSelf();
            CastTrayNotifier.refresh(this);
            return START_NOT_STICKY;
        }
        if (ACTION_UP.equals(action)) {
            String cfg = intent.getStringExtra(EXTRA_WG_CONFIG);
            int fgsType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
                    ? ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE
                    : 0;
            CastTrayNotifier.startForeground(this, fgsType);
            CastTrayNotifier.ensureTrayService(this);
            establishTun(cfg);
            return START_STICKY;
        }
        return START_NOT_STICKY;
    }

    private void establishTun(String wgConfig) {
        tearDown();
        try {
            String address = WireGuardQuickConfig.parseAddress(wgConfig);
            Builder b = new Builder();
            b.setSession("AndroidCast RA");
            if (address != null) {
                String[] parts = address.split("/");
                b.addAddress(InetAddress.getByName(parts[0]),
                        parts.length > 1 ? Integer.parseInt(parts[1]) : 32);
            }
            for (String app : WireGuardQuickConfig.parseIncludedApplications(wgConfig)) {
                try {
                    b.addAllowedApplication(app);
                } catch (PackageManager.NameNotFoundException e) {
                    Log.w(TAG, "IncludedApplications skip unknown package: " + app);
                }
            }
            for (String route : WireGuardQuickConfig.parseAllowedRoutes(wgConfig)) {
                String[] rp = route.split("/");
                if (rp.length >= 2) {
                    b.addRoute(rp[0], Integer.parseInt(rp[1]));
                }
            }
            b.setMtu(1280);
            tun = b.establish();
            Log.i(TAG, "VPN interface established");
            CastTrayNotifier.refresh(this);
        } catch (Exception e) {
            Log.e(TAG, "VPN establish failed", e);
        }
    }

    private void tearDown() {
        if (tun != null) {
            try {
                tun.close();
            } catch (Exception ignored) {
            }
            tun = null;
        }
    }

    @Override
    public void onDestroy() {
        tearDown();
        super.onDestroy();
    }
}
