
<%----- File integrity check-----%>
<%@ page import="java.io.*, java.util.*, java.security.*" %>
<%@ page import="com.google.gson.Gson" %>
<%@ include file="utils.jspf" %>
<%@ page import="org.owasp.encoder.Encode"%>


<%!
    class BuildInfo {
        String status;
        Map<String, String> errors = new HashMap<>();
        Map<String, String> warnings = new HashMap<>();
        Map<String, Object> extraInfo = new HashMap<>();
        List<String> resolutions;

        BuildInfo(Map<String, Object> files, boolean isOldHashPresent) {
            this.extraInfo.put("isOldHashPresent", isOldHashPresent);
            this.resolutions = new ArrayList<>();
            Boolean isValid = (Boolean) files.get("isValid");
            Map<String, String> details = (Map<String, String>) files.get("details");
            Map<String, String> warnings = (Map<String, String>) files.get("warnings");

            if (!isValid) {
                if (details != null && !details.isEmpty()) {
                    this.status = "fail";
                    for (Map.Entry<String, String> entry : details.entrySet()) {
                        this.errors.put(entry.getKey(), entry.getValue());
                    }

                } else if (warnings != null && !warnings.isEmpty()) {
                    this.status = "passWithWarnings";
                    for (Map.Entry<String, String> entry : warnings.entrySet()) {
                        this.warnings.put(entry.getKey(), entry.getValue());
                    }
                    
                } 
                List<String> resolutions = (List<String>) files.get("resolutions");
                this.resolutions.addAll(resolutions);
            } else {
                this.status = "pass";
            }
        }
    }

    public Map<String, Object> checkFilesAndHashes(ServletContext application, Properties prop, Properties oldHashProps) {
        Map<String, String> validationErrors = new LinkedHashMap<>();
        Map<String, String> validationWarnings = new LinkedHashMap<>();
        // List<String> validationResolutions = new ArrayList<>();
        Set<String> validationResolutions = new LinkedHashSet<>();
        boolean isValid = true;

        for (String key : prop.stringPropertyNames()) {

            boolean isFileKey = key.startsWith("file.") && key.endsWith(".path");
            boolean isCustomKey = key.startsWith("custom.") && key.endsWith(".path");

            if (isFileKey || isCustomKey) {
                String baseKey = key.substring(0, key.lastIndexOf(".path"));
                String filePath = prop.getProperty(key);
                String expectedHash = prop.getProperty(baseKey + ".hash", "N/A");

                File file = new File(getRealPath(application, filePath));

                try {
                    if (!file.exists()) {
                        validationErrors.put(filePath, "E: File Missing");
                        validationResolutions.add(resolutionMessages.getOrDefault("E04", "Please Redeploy Plugin"));
                        isValid = false;
                    } else {
                        // Use oldHashProps if available
                        String computedHash;
                        if (oldHashProps.containsKey(baseKey + ".hash")) {
                            computedHash = oldHashProps.getProperty(baseKey + ".hash");
                        } else {
                            computedHash = getMD5Checksum(getRealPath(application, filePath));
                        }
                        if (!computedHash.equals(expectedHash)) {
                            if (isCustomKey) {
                                validationWarnings.put(filePath, "E: File Possibly Modified");
                                validationResolutions.add(resolutionMessages.getOrDefault("E14", "Verify custom configuration files"));
                            } else {
                                validationErrors.put(filePath, "E: File Damaged");
                                validationResolutions.add(resolutionMessages.getOrDefault("E05", "Please Redeploy Plugin"));
                            }
                            isValid = false;
                        }
                    }
                } catch (NoSuchAlgorithmException | IOException e) {
                    validationErrors.put(filePath, "E: Error computing hash: " + e.getMessage());
                    isValid = false;
                }
            }
        }

        // Return structured result: Only return details if something is wrong
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("isValid", isValid);
        if (!isValid) {
            result.put("details", validationErrors);
            result.put("warnings", validationWarnings);
            // result.put("resolutions", validationResolutions);
            result.put("resolutions", new ArrayList<>(validationResolutions));
        }
        return result;
    }

    Properties loadOldHashProperties(ServletContext application) {
        Properties oldHashProps = new Properties();
        String oldPropPath = getRealPath(application, "VitaraCharts/utils/CheckHealth/oldHash.properties");
        File oldHashFile = new File(oldPropPath);

        if (!oldHashFile.exists()) {
            return oldHashProps;  // Return an empty Properties object
        }

        try (FileInputStream fis = new FileInputStream(oldHashFile)) {
            oldHashProps.load(fis);
        } catch (IOException e) {
            //e.printStackTrace();
        }
        return oldHashProps;
    }
%>

<% 
    Properties prop = readStateProperties(getRealPath(application, "VitaraCharts/utils/CheckHealth/state.properties"));    
    String appVersion = prop.getProperty("app.version");

    // Load oldHash.properties (if it exists)
    Properties oldHashProps = loadOldHashProperties(application);
    boolean isPresent = !oldHashProps.isEmpty();
    //validating fileExistance & integrity
    Map<String, Object> fileResults = checkFilesAndHashes(application, prop, oldHashProps);

    BuildInfo build = new BuildInfo(fileResults, isPresent);
    Gson gson = new Gson();
    String json = gson.toJson(build);
    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");
    out.print(json);
    out.flush();
%>
