package com.aip.gateway.api.aip;

import com.aip.gateway.api.aip.model.AipConfig;
import com.microsoft.informationprotection.*;
import com.microsoft.informationprotection.file.*;
import com.microsoft.informationprotection.internal.callback.FileHandlerObserver;
import lombok.extern.slf4j.Slf4j;

import java.util.Collection;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@Slf4j
public class Action {
    private AuthDelegateImpl authDelegate;
    private IFileProfile fileProfile;
    private IFileEngine fileEngine;
    private MipContext mipContext;
    private String userName;
    public Action(AipConfig aipConfig) throws InterruptedException, ExecutionException
    {
        try {
            authDelegate = new AuthDelegateImpl(aipConfig);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // Initialize MIP For File SDK components.
        MIP.initialize(MipComponent.FILE, "C:\\DEV\\SOLUTION\\IIS\\AipGateway.API\\bin\\amd64");

        // Create MIP Configuration
        // MIP Configuration can be used to set various delegates, feature flags, and other SDK behavior.
        //MipConfiguration mipConfiguration = new MipConfiguration(appInfo, "mip_data", LogLevel.TRACE, false);

        // Create MipContext from MipConfiguration
        //mipContext = MIP.createMipContext(mipConfiguration);

        // Create the FileProfile and Engine.
        fileProfile = CreateFileProfile();
        fileEngine = CreateFileEngine(fileProfile);
    }

    private IFileProfile CreateFileProfile() throws InterruptedException, ExecutionException
    {
        // The ConsentDelegate is required for all FileProfiles, but fires only when connecting to AD RMS.
        ConsentDelegateImpl consentDelegate = new ConsentDelegateImpl();

        // Create FileProfileSettings, passing in to LoadFileProfileAsync() and getting the result.
        FileProfileSettings fileProfileSettings = new FileProfileSettings(mipContext, CacheStorageType.ON_DISK, consentDelegate);
        Future<IFileProfile> fileProfileFuture = MIP.loadFileProfileAsync(fileProfileSettings);
        IFileProfile fileProfile = fileProfileFuture.get();
        return fileProfile;
    }

    private IFileEngine CreateFileEngine(IFileProfile profile) throws InterruptedException, ExecutionException
    {
        // Create the file engine, passing in the username as the first parameter.
        // This sets the engineId to the username, making it easier to load the cached engine.
        // Using cached engines reduces service road trips and will use cached use licenses for protected content.
        FileEngineSettings engineSettings = new FileEngineSettings(userName, authDelegate, "", "en-US");

        // Uncomment to set a functionality filter. These filters are useful for filtering or including labels based on protection type.
        // The example below will result in removal of labels with user-defined permissions.
        //engineSettings.configureFunctionality(FunctionalityFilterType.CUSTOM, false);

        // Set the user identity for the engine. This aids in service discovery.
        engineSettings.setIdentity(new Identity(userName));

        // Add the engine and get the result.
        Future<IFileEngine> fileEngineFuture = fileProfile.addEngineAsync(engineSettings);
        IFileEngine fileEngine = fileEngineFuture.get();
        return fileEngine;
    }

    private IFileHandler CreateFileHandler(FileOptions options, IFileEngine engine) throws InterruptedException, ExecutionException
    {
        // Create a FileHandler. FileHandlers are used to perform all file-specific operations.
        FileHandlerObserver observer = new FileHandlerObserver();
        Future<IFileHandler> handlerFuture = engine.createFileHandlerAsync(options.InputFilePath, options.InputFilePath, options.GenerateChangeAuditEvent, observer, null);
        return handlerFuture.get();
    }

    public void ListLabels()
    {
        // Use the FileEngine to get all labels for the user and display on screen.
        Collection<Label> labels = fileEngine.getSensitivityLabels();
        labels.forEach(label -> {
            System.out.println(label.getName() + " : " + label.getId());
            if(label.getChildren().size() > 0)
            {
                label.getChildren().forEach(child -> {
                    System.out.println("\t" + child.getName() + " : " + child.getId());
                });
            }
        });
    }

    public boolean SetLabel(FileOptions options) throws InterruptedException, ExecutionException
    {
        // Create a new FileHandler for the specified file and options.
        IFileHandler fileHandler = CreateFileHandler(options, fileEngine);

        // LabelingOptions is used to set specific attributes about the labeling operation.
        // If the labeling operations throws a JustificationRequiredException, use the
        // setJustificationMessage() and isDowngradeJustified() then retry.
        LabelingOptions labelingOptions = new LabelingOptions();
        labelingOptions.setAssignmentMethod(options.AssignmentMethod);

        //labelingOptions.isDowngradeJustified(true);
        //labelingOptions.setJustificationMessage("My Justification Message");

        Label label = fileEngine.getLabelById(options.LabelId);

        // Attempt to set the label on the FileHandler.
        // The ProtectionSettings object can be used to write protection as another user
        // or to change the pfile extension behavior.
        fileHandler.setLabel(label, labelingOptions, new ProtectionSettings());

        // Check to see if handler has been modified. If not, skip commit.
        boolean result = false;
        if(fileHandler.isModified())
        {
            // Commit the result. Will return false if no changes were made.
            // Given that it's gated on the isModified() property, this should always be true.
            result = fileHandler.commitAsync(options.OutputFilePath).get();
        }

        return result;
    }

    public ContentLabel GetLabel(FileOptions options) throws InterruptedException, ExecutionException
    {
        // Create a FileHandler then get the label from the handler.
        IFileHandler fileHandler = CreateFileHandler(options, fileEngine);
        return fileHandler.getLabel();
    }

    public ProtectionDescriptor GetProtection(FileOptions options) throws InterruptedException, ExecutionException
    {
        // Create a FileHandler then get the protection descriptor from the handler.
        IFileHandler fileHandler = CreateFileHandler(options, fileEngine);
        return fileHandler.getProtection().getProtectionDescriptor();
    }
}
