package grpc.server;

import Coordinator_Worker.Coordinator;
import ch.qos.logback.classic.Logger;
import grpc.Request;
import grpc.Response;
import grpc.searchServiceGrpc;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

public class grpcServer {
    private static final Logger logger = (Logger) LoggerFactory.getLogger(grpcServer.class);

    // Method to start the gRPC server
    public static void startGrpcServer() throws Exception {
        System.out.println("Starting gRPC Server");
        // Create a gRPC server with the specified port and service implementation
        Server server = ServerBuilder.forPort(8080)
                .addService(new SearchServiceImpl())
                .executor(Executors.newFixedThreadPool(10)) // Adjust the pool size as needed
                .build();

        // Start the gRPC server and wait for it to terminate
        server.start();
        server.awaitTermination();
    }

    // Implementation of the gRPC service
    private static class SearchServiceImpl extends searchServiceGrpc.searchServiceImplBase {
        // gRPC method to handle search requests asynchronously
        @Override
        public void search(Request request, StreamObserver<Response> responseObserver) {
            // Use a separate thread or executor for handling each request asynchronously
            Executors.newCachedThreadPool().submit(() -> {
                try {
                    // Step 1: Retrieve Inverse Document Frequency (IDF) from Coordinator
                    TreeMap<String, Double> IDF = Coordinator.startCoordinator(request.getInput());

                    // Create a new TreeMap with a custom comparator for sorting by values in reverse order
                    TreeMap<String, Double> sortedIDF = new TreeMap<>(new Comparator<String>() {
                        @Override
                        public int compare(String key1, String key2) {
                            int valueCompare = IDF.get(key2).compareTo(IDF.get(key1));
                            return (valueCompare == 0) ? key1.compareTo(key2) : valueCompare;
                        }
                    });

                    // Put all entries from IDF into the sortedIDF TreeMap
                    sortedIDF.putAll(IDF);
                    //contain just the first 10 element from sortedIDF
                    TreeMap<String,Double> first10=new TreeMap<>();
                    int count=0;
                    for(Map.Entry<String,Double> entry: sortedIDF.entrySet()) {
                        if(count==10) break;
                        first10.put(entry.getKey(),entry.getValue());
                        count++;
                    }
                    // Step 2: Build the response with a TreeMap which Coordinator provides
                    Response.Builder responseBuilder = Response.newBuilder();
                    for (Map.Entry<String, Double> entry : first10.entrySet()) {
                        responseBuilder.putOutput(entry.getKey(), entry.getValue());
                    }
                    logger.info("The Response which send by gRPC: {}",first10);
                    Response response = responseBuilder.build();


                    // Step 3: Send the response to the client
                    responseObserver.onNext(response);
                    responseObserver.onCompleted();
                } catch (Exception e) {
                    e.printStackTrace();
                    // Handle exceptions appropriately
                }
            });
        }
    }
}
