/*-
 * ~~~~~~licensing~~~~~~
 * entaxy-audit
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
package ru.entaxy.audit.service.impl;


import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.LongAdder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.security.auth.Subject;

import org.osgi.service.event.Event;

import ru.entaxy.audit.data.AuditEvent;
import ru.entaxy.audit.data.Severity;
import ru.entaxy.audit.utils.AuditHelper;
import ru.entaxy.audit.utils.CommandWeight;

public class OSGIEventModule {

    private Map<String, LongAdder> processedCommands = new ConcurrentHashMap<>();
    private Map<String, LongAdder> skippedCommands = new ConcurrentHashMap<>();

    private final Set<String> targets = new HashSet<String>() {{
        add("jaas");
    }};

    private final static Pattern COMMAND_PATTERN = Pattern.compile("^(.+):([A-Za-z-]+)\\s?+(.+)?$");
    private final static Pattern FILE_PATTERN = Pattern.compile("^Updating ([a-zA-Z]+)\\s+(from)?\\s?(.+)$");

    public void onEvent(Event event) {
        String command = (String) event.getProperty("command");
        if (command == null) {
            return;
        }
        Subject subject = (Subject) event.getProperty("subject");
        boolean processed = false;
        Matcher m = checkCommand(command);
        if (m != null && subject != null) {
            String suser = AuditHelper.findRemoteUser(subject);
            String address = AuditHelper.findAddress(subject);
            String target = m.group(1);
            String commandName = m.group(2);
            String arguments = m.group(3);
            if (targets.contains(target)) {
                AuditEvent auditEvent = AuditEvent.AuditLoggingEventBuilder.getInstance()
                        .target(target)
                        .suser(suser)
                        .src(address)
                        .category(commandName)
                        .severity(CommandWeight.getByTarget(target))
                        .message(arguments == null ? "" : arguments).build();
                AuditHelper.log(auditEvent);
                processed = true;
            }
        }
        Map<String, LongAdder> target = processed ? processedCommands : skippedCommands;
        target.computeIfAbsent(command, (s) -> new LongAdder()).increment();
    }

    private Matcher checkCommand(String command) {
        Matcher m = COMMAND_PATTERN.matcher(command);
        if (m.find()) {
            return m;
        }
        return null;
    }

    public void onFileChange(Event event) {
        String message = (String) event.getProperty("message");
        Matcher m = FILE_PATTERN.matcher(message);
        if (m.find()) {
            String filename = m.group(3);
            String changeSubject = m.group(1);
            String target = "Update " + changeSubject;
            if (changeSubject.equals("bundle") || changeSubject.equals("configuration")) {
                AuditEvent auditEvent = AuditEvent.AuditLoggingEventBuilder.getInstance()
                        .target(target)
                        .suser("local")
                        .src("localhost")
                        .category(filename)
                        .severity(Severity.WARNING)
                        .message(message).build();
                AuditHelper.log(auditEvent);
                processedCommands.computeIfAbsent(target, (s) -> new LongAdder()).increment();
            }
            skippedCommands.computeIfAbsent(target, (s) -> new LongAdder()).increment();
        }
    }
}
