package tech.nevets.tvpn.wg;

import tech.nevets.tvpn.Logger;
import tech.nevets.tvpn.Utils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

import static tech.nevets.tvpn.Utils.*;

public class WireGuardHandler {
    private static final Logger LOGGER = new Logger(WireGuardHandler.class);

    public static void loadTunnel(Path tunnelConfig) throws IOException {
        Files.copy(tunnelConfig, Path.of(WG_CONF_DIR + tunnelConfig.getFileName().toString()));
    }

    public static boolean deleteTunnel(String tunnelName) {
        File f = new File(WG_CONF_DIR + tunnelName + ".conf.dpapi");
        return f.delete();
    }

    public static void startTunnel(String tunnelName) {
        try {
            Process proc = new ProcessBuilder()
                    .directory(APP_DIR)
                    .command("cmd", "/C", "wireguard.exe", "/installtunnelservice", WG_CONF_DIR + tunnelName + ".conf.dpapi")
                    .inheritIO()
                    .start();
            System.out.println("Start Tunnel: " + proc.waitFor());
            if (getWGShow() == null) return;
            for (float f = 0; getWGShow().isEmpty(); f += 0.5f) {
            //while (getWGShow().isEmpty()) {
                if (f >= 12) {
                    System.out.println("Start tunnel timed out");
                    return;
                }
                System.out.println("Waiting for wg start... " + f + "s");
                Thread.sleep(500);
            }
            System.out.println("Tunnel Started");
        } catch (IOException | InterruptedException e) {
            LOGGER.error(e.getMessage());
        }
    }

    public static void stopTunnel(String tunnelName) {
        try {
            Process proc = new ProcessBuilder()
                    .directory(APP_DIR)
                    .command("cmd", "/C", "wireguard.exe", "/uninstalltunnelservice", tunnelName)
                    .inheritIO()
                    .start();
            System.out.println("Stop Tunnel: " + proc.waitFor());
            if (getWGShow() == null) return;
            for (float f = 0; !getWGShow().isEmpty(); f += 0.5f) {
//            while (!getWGShow().isEmpty()) {
                if (f >= 12) {
                    System.out.println("Stop tunnel timed out");
                    return;
                }
                System.out.println("Waiting for wg stop... " + f + "s");
                Thread.sleep(500);
            }
            System.out.println("Tunnel Stopped");
        } catch (IOException | InterruptedException e) {
            LOGGER.error(e.getMessage());
        }
    }

    public static List<String> getTunnelConfigs() {
        List<Path> filePaths = new ArrayList<>();
        Path path = Path.of(Utils.WG_CONF_DIR);
        try (Stream<Path> ps = Files.walk(path)) {
            ps.filter(Files::isRegularFile)
                    .forEach(filePaths::add);
            List<String> fileNames = new ArrayList<>();
            for(Path p : filePaths) {
                String fullPath = p.toString();
                fileNames.add(fullPath.substring(fullPath.lastIndexOf("\\") + 1));
            }
            return fileNames;
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
            return new ArrayList<>();
        }
    }

    public static List<String> getActiveTunnels() {
        String[] rSplit = getWGShowLines();
        List<String> tunnels = new ArrayList<>();
        for (String s : rSplit) {
            if (s.toLowerCase().contains("interface")) {
                tunnels.add(s.split(":")[1].trim());
            }
        }
        return tunnels;
    }

    private static String getWGShow() {
        ProcessBuilder pb = new ProcessBuilder();
        pb.command("cmd", "/C", "wg.exe", "show");
        try {
            Process p = pb.start();
            return new String(p.getInputStream().readAllBytes());
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
            return null;
        }
    }

    private static String[] getWGShowLines() {
        String result = getWGShow();
        if (result == null) {
            return new String[]{};
        }
        return result.split("\n");
    }

    public static void getActiveConfig(String tunnelName) {
        ProcessBuilder pb = new ProcessBuilder();
        System.out.println("Tunnel Name: " + tunnelName);
        String outFile = Utils.APP_DIR + "/" + tunnelName + ".conf";
        System.out.println("Out File: " + outFile);
        pb.redirectOutput(new File(outFile));
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb.command("cmd", "/C", "wg.exe", "showconf", tunnelName);
        try {
            Process p = pb.start();
            p.waitFor();
        } catch (IOException | InterruptedException e) {
            LOGGER.error(e.getMessage());
        }
    }

    public static boolean isActiveTunnel() {
        getActiveTunnels().forEach(System.out::println);

        return !getActiveTunnels().isEmpty();
    }
}
