package eu.starsong.ghidra.endpoints;

    import com.google.gson.JsonObject;
    import com.sun.net.httpserver.HttpExchange;
    import com.sun.net.httpserver.HttpServer;
    import ghidra.framework.plugintool.PluginTool;
    import ghidra.program.model.listing.Program;
    import ghidra.program.model.symbol.Symbol;
    import ghidra.program.model.symbol.SymbolIterator;
    import ghidra.program.model.symbol.SymbolTable;
    import ghidra.util.Msg;

    import java.io.IOException;
    import java.util.*;

    public class SymbolEndpoints extends AbstractEndpoint {

        private PluginTool tool;
        
        // Updated constructor to accept port
        public SymbolEndpoints(Program program, int port) {
            super(program, port); // Call super constructor
        }
        
        public SymbolEndpoints(Program program, int port, PluginTool tool) {
            super(program, port);
            this.tool = tool;
        }
        
        @Override
        protected PluginTool getTool() {
            return tool;
        }

        @Override
        public void registerEndpoints(HttpServer server) {
            server.createContext("/symbols/imports", this::handleImports);
            server.createContext("/symbols/exports", this::handleExports);
            server.createContext("/symbols", this::handleSymbols);
        }
        
        public void handleSymbols(HttpExchange exchange) throws IOException {
            try {
                if ("GET".equals(exchange.getRequestMethod())) {
                    Map<String, String> qparams = parseQueryParams(exchange);
                    int offset = parseIntOrDefault(qparams.get("offset"), 0);
                    int limit = parseIntOrDefault(qparams.get("limit"), 100);
                    
                    Program program = getCurrentProgram();
                    if (program == null) {
                        sendErrorResponse(exchange, 400, "No program loaded", "NO_PROGRAM_LOADED");
                        return;
                    }
                    
                    List<Map<String, Object>> symbols = new ArrayList<>();
                    SymbolTable symbolTable = program.getSymbolTable();
                    SymbolIterator symbolIterator = symbolTable.getAllSymbols(true);
                    
                    while (symbolIterator.hasNext()) {
                        Symbol symbol = symbolIterator.next();
                        Map<String, Object> symbolInfo = new HashMap<>();
                        symbolInfo.put("name", symbol.getName());
                        symbolInfo.put("address", symbol.getAddress().toString());
                        symbolInfo.put("namespace", symbol.getParentNamespace().getName());
                        symbolInfo.put("type", symbol.getSymbolType().toString());
                        symbolInfo.put("isPrimary", symbol.isPrimary());
                        
                        // Add HATEOAS links
                        Map<String, Object> links = new HashMap<>();
                        Map<String, String> selfLink = new HashMap<>();
                        selfLink.put("href", "/symbols/" + symbol.getAddress().toString());
                        links.put("self", selfLink);
                        symbolInfo.put("_links", links);
                        
                        symbols.add(symbolInfo);
                    }
                    
                    // Build response with HATEOAS links
                    eu.starsong.ghidra.api.ResponseBuilder builder = new eu.starsong.ghidra.api.ResponseBuilder(exchange, port)
                        .success(true);
                    
                    // Apply pagination and get paginated items
                    List<Map<String, Object>> paginatedSymbols = applyPagination(symbols, offset, limit, builder, "/symbols");
                    
                    // Set the paginated result
                    builder.result(paginatedSymbols);
                    
                    // Add program link
                    builder.addLink("program", "/program");
                    
                    sendJsonResponse(exchange, builder.build(), 200);
                } else {
                    sendErrorResponse(exchange, 405, "Method Not Allowed", "METHOD_NOT_ALLOWED");
                }
            } catch (Exception e) {
                Msg.error(this, "Error handling /symbols endpoint", e);
                sendErrorResponse(exchange, 500, "Internal Server Error: " + e.getMessage(), "INTERNAL_ERROR");
            }
        }

        public void handleImports(HttpExchange exchange) throws IOException {
            try {
                if ("GET".equals(exchange.getRequestMethod())) {
                    Map<String, String> qparams = parseQueryParams(exchange);
                    int offset = parseIntOrDefault(qparams.get("offset"), 0);
                    int limit = parseIntOrDefault(qparams.get("limit"), 100);
                    
                    Program program = getCurrentProgram();
                    if (program == null) {
                        sendErrorResponse(exchange, 400, "No program loaded", "NO_PROGRAM_LOADED");
                        return;
                    }
                    
                    List<Map<String, Object>> imports = new ArrayList<>();
                    for (Symbol symbol : program.getSymbolTable().getExternalSymbols()) {
                        Map<String, Object> imp = new HashMap<>();
                        imp.put("name", symbol.getName());
                        imp.put("address", symbol.getAddress().toString());
                        
                        // Add HATEOAS links
                        Map<String, Object> links = new HashMap<>();
                        Map<String, String> selfLink = new HashMap<>();
                        selfLink.put("href", "/symbols/imports/" + symbol.getAddress().toString());
                        links.put("self", selfLink);
                        imp.put("_links", links);
                        
                        imports.add(imp);
                    }
                    
                    // Build response with HATEOAS links
                    eu.starsong.ghidra.api.ResponseBuilder builder = new eu.starsong.ghidra.api.ResponseBuilder(exchange, port)
                        .success(true);
                    
                    // Apply pagination and get paginated items
                    List<Map<String, Object>> paginated = applyPagination(imports, offset, limit, builder, "/symbols/imports");
                    
                    // Set the paginated result
                    builder.result(paginated);
                    
                    // Add additional links
                    builder.addLink("program", "/program");
                    builder.addLink("symbols", "/symbols");
                    
                    sendJsonResponse(exchange, builder.build(), 200);
                } else {
                    sendErrorResponse(exchange, 405, "Method Not Allowed", "METHOD_NOT_ALLOWED");
                }
            } catch (Exception e) {
                Msg.error(this, "Error in /symbols/imports endpoint", e);
                sendErrorResponse(exchange, 500, "Internal server error: " + e.getMessage(), "INTERNAL_ERROR");
            }
        }

        public void handleExports(HttpExchange exchange) throws IOException {
            try {
                if ("GET".equals(exchange.getRequestMethod())) {
                    Map<String, String> qparams = parseQueryParams(exchange);
                    int offset = parseIntOrDefault(qparams.get("offset"), 0);
                    int limit = parseIntOrDefault(qparams.get("limit"), 100);
                    
                    Program program = getCurrentProgram();
                    if (program == null) {
                        sendErrorResponse(exchange, 400, "No program loaded", "NO_PROGRAM_LOADED");
                        return;
                    }
                    
                    List<Map<String, Object>> exports = new ArrayList<>();
                    SymbolTable table = program.getSymbolTable();
                    SymbolIterator it = table.getAllSymbols(true);
                    
                    while (it.hasNext()) {
                        Symbol s = it.next();
                        if (s.isExternalEntryPoint()) {
                            Map<String, Object> exp = new HashMap<>();
                            exp.put("name", s.getName());
                            exp.put("address", s.getAddress().toString());
                            
                            // Add HATEOAS links
                            Map<String, Object> links = new HashMap<>();
                            Map<String, String> selfLink = new HashMap<>();
                            selfLink.put("href", "/symbols/exports/" + s.getAddress().toString());
                            links.put("self", selfLink);
                            exp.put("_links", links);
                            
                            exports.add(exp);
                        }
                    }
                    
                    // Build response with HATEOAS links
                    eu.starsong.ghidra.api.ResponseBuilder builder = new eu.starsong.ghidra.api.ResponseBuilder(exchange, port)
                        .success(true);
                    
                    // Apply pagination and get paginated items
                    List<Map<String, Object>> paginated = applyPagination(exports, offset, limit, builder, "/symbols/exports");
                    
                    // Set the paginated result
                    builder.result(paginated);
                    
                    // Add additional links
                    builder.addLink("program", "/program");
                    builder.addLink("symbols", "/symbols");
                    
                    sendJsonResponse(exchange, builder.build(), 200);
                } else {
                    sendErrorResponse(exchange, 405, "Method Not Allowed", "METHOD_NOT_ALLOWED");
                }
            } catch (Exception e) {
                Msg.error(this, "Error in /symbols/exports endpoint", e);
                sendErrorResponse(exchange, 500, "Internal server error: " + e.getMessage(), "INTERNAL_ERROR");
            }
        }

        // parseIntOrDefault is inherited from AbstractEndpoint
    }
