package outbackcdx;

import outbackcdx.auth.Authorizer;
import outbackcdx.auth.JwtAuthorizer;
import outbackcdx.auth.KeycloakConfig;
import outbackcdx.auth.NullAuthorizer;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URL;
import java.nio.channels.Channel;
import java.nio.channels.ServerSocketChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void usage() {
        System.err.println("Usage: java " + Main.class.getName() + " [options...]");
        System.err.println("");
        System.err.println("  -b bindaddr           Bind to a particular IP address");
        System.err.println("  -d datadir            Directory to store index data under");
        System.err.println("  -i                    Inherit the server socket via STDIN (for use with systemd, inetd etc)");
        System.err.println("  -j jwks-url perm-path Use JSON Web Tokens for authorization");
        System.err.println("  -k url realm clientid Use a Keycloak server for authorization");
        System.err.println("  -p port               Local port to listen on");
        System.err.println("  -t count              Number of web server threads");
        System.err.println("  -v                    Verbose logging");
        System.err.println();
        System.err.println("Secondary mode (runs read-only; polls upstream server on 'collection-url' for changes)");
        System.err.println("  --primary collection-url              URL of collection on upstream primary to poll for changes");
        System.err.println("  --update-interval poll-interval       Polling frequency for upstream changes, in seconds. Default: 10");
        System.exit(1);
    }

    public static void main(String args[]) {
        boolean undertow = false;
        String host = null;
        int port = 8080;
        int webThreads = Runtime.getRuntime().availableProcessors();
        boolean inheritSocket = false;
        File dataPath = new File("data");
        boolean verbose = false;
        Authorizer authorizer = new NullAuthorizer();
        int pollingInterval = 10;
        String collectionUrl = null;

        Map<String,Object> dashboardConfig = new HashMap<>();
        dashboardConfig.put("featureFlags", FeatureFlags.asMap());

        for (int i = 0; i < args.length; i++) {
            switch (args[i]) {
                case "-u":
                    undertow = true;
                    break;
                case "-p":
                    port = Integer.parseInt(args[++i]);
                    break;
                case "-b":
                    host = args[++i];
                    break;
                case "-d":
                    dataPath = new File(args[++i]);
                    break;
                case "-i":
                    inheritSocket = true;
                    break;
                case "-j":
                    try {
                        authorizer = new JwtAuthorizer(new URL(args[++i]), args[++i]);
                    } catch (MalformedURLException e) {
                        System.err.println("Malformed JWKS URL in -j option");
                        System.exit(1);
                    }
                    break;
                case "-k":
                    KeycloakConfig keycloakConfig = new KeycloakConfig(args[++i], args[++i], args[++i]);
                    authorizer = keycloakConfig.toAuthorizer();
                    dashboardConfig.put("keycloak", keycloakConfig);
                    break;
                case "-v":
                    verbose = true;
                    break;
                case "-t":
                    webThreads = Integer.parseInt(args[++i]);
                    break;
                case "--primary":
                    collectionUrl = args[i++];
                    break;
                case "--update-interval":
                    pollingInterval = Integer.parseInt(args[i++]);
                    break;
                default:
                    usage();
                    break;
            }
        }

        try (DataStore dataStore = new DataStore(dataPath)) {
            Webapp controller = new Webapp(dataStore, verbose, dashboardConfig);
            if (undertow) {
                UWeb.UServer server = new UWeb.UServer(host, port, controller, authorizer);
                server.start();
                System.out.println("OutbackCDX http://" + (host == null ? "localhost" : host) + ":" + port);
                Thread.sleep(Long.MAX_VALUE);
            } else {
                ServerSocket socket = openSocket(host, port, inheritSocket);
                Web.Server server = new Web.Server(socket, controller, authorizer);
                ExecutorService threadPool = Executors.newFixedThreadPool(webThreads);
                try {
                    server.setAsyncRunner(threadPool::execute);
                    server.start();
                    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                        server.stop();
                        dataStore.close();
                    }));
                    System.out.println("OutbackCDX http://" + (host == null ? "localhost" : host) + ":" + port);
                    Thread.sleep(Long.MAX_VALUE);
                } finally {
                    threadPool.shutdown();
                }
            }
            if (collectionUrl != null){
                ChangePollingThread cpt = new ChangePollingThread(collectionUrl, pollingInterval, dataStore);
                cpt.setDaemon(true);
                cpt.start();
            }
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
    }

    private static ServerSocket openSocket(String host, int port, boolean inheritSocket) throws IOException {
        ServerSocket socket;Channel channel = System.inheritedChannel();
        if (inheritSocket && channel instanceof ServerSocketChannel) {
            socket = ((ServerSocketChannel) channel).socket();
        } else {
            socket = new ServerSocket(port, -1, InetAddress.getByName(host));
        }
        return socket;
    }
}

@@ -3967,19 +3967,19 @@
  = args%5B
-i
 ++
+i
 %5D;%0A     
@@ -4102,19 +4102,19 @@
 nt(args%5B
-i
 ++
+i
 %5D);%0A    
@@ -4961,16 +4961,266 @@
 reads);%0A
+                if (collectionUrl != null)%7B%0A                    ChangePollingThread cpt = new ChangePollingThread(collectionUrl, pollingInterval, dataStore);%0A                    cpt.setDaemon(true);%0A                    cpt.start();%0A                %7D%0A
         
@@ -5746,24 +5746,24 @@
 shutdown();%0A
+
             
@@ -5786,238 +5786,8 @@
   %7D%0A
-            if (collectionUrl != null)%7B%0A                ChangePollingThread cpt = new ChangePollingThread(collectionUrl, pollingInterval, dataStore);%0A                cpt.setDaemon(true);%0A                cpt.start();%0A            %7D%0A
     

make the polling thread start in the right place; find arguments correctly