package com.aip.gateway.api.aip.manager;

import com.aip.gateway.api.aip.AuthDelegateImpl;
import com.aip.gateway.api.aip.model.*;
import com.aip.gateway.api.aip.utils.Utilities;
import com.microsoft.informationprotection.*;
import com.microsoft.informationprotection.file.FileHandler;
import com.microsoft.informationprotection.file.IFileStatus;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
@Getter
public class AipFileManager extends  AipFileManagerBase {
    public AipFileManager(AipConfig aipConfig) {
        super(aipConfig);
    }

    public void dispose() {
        dispose(true);
    }

    public boolean initialize() {
        try {
            _authDelegate = new AuthDelegateImpl(aipConfig);
        }
        catch (Exception e) {
            setError(1, "MIP.Initialize Failed. AuthDelegateImpl Create Failed.", e.getMessage());
            return false;
        }

        try {
            String mipLibPath = System.getProperty("user.dir") + File.separator + "amd64";
            MIP.initialize(MipComponent.FILE, mipLibPath);
        }
        catch (Exception ex) {
            setError(1, "MIP.Initialize Failed.", ex.getMessage());
            return false;
        }

        MipConfiguration mipConfiguration = new MipConfiguration(appInfo, aipConfig.getMipData(), LogLevel.INFO, false);
        _mipContext = MIP.createMipContext(mipConfiguration);
        return true;
    }

    public boolean createProfile() {
        if (!checkLoading()) return false;

        if (!_fileManager.createProfile(_mipContext)) {
            setError(11, "AipFileManager::CreateProfile_fileManager Failed.", _fileManager.getLastErrMsg());
            return false;
        }
        if (!_policyManager.createProfile(_mipContext)) {
            setError(12, "AipFileManager::CreateProfile_policyManager Failed.", _policyManager.getLastErrMsg());
            return false;
        }
        if (!_protectionManager.createProfile(_mipContext)) {
            setError(13, "AipFileManager::CreateProfile_protectionManager Failed.", _protectionManager.getLastErrMsg());
            return false;
        }
        return true;
    }
    public boolean createEngine() {
        if (!checkLoading()) return false;

        Identity identity = new Identity(aipConfig.getEMail());
        if (!_fileManager.createEngine(identity, _authDelegate)) {
            setError(21, "AipFileManager::CreateEngine_fileManager Failed.", _fileManager.getLastErrMsg());
            return false;
        }
        if (!_policyManager.createEngine(identity, _authDelegate)) {
            setError(22, "AipFileManager::CreateEngine_policyManager Failed.", _policyManager.getLastErrMsg());
            return false;
        }
        if (!_protectionManager.createEngine(identity, _authDelegate)) {
            setError(23, "AipFileManager::CreateEngine_protectionManager Failed.", _protectionManager.getLastErrMsg());
            return false;
        }
        return true;
    }
    public List<AipLabel> sensitivityLabels() {
        if (!checkLoading()) return null;
        return aipLabel2AppLabel(_fileManager.sensitivityLabels());
    }
    public List<AipLabel> listSensitivityLabels() {
        if (!checkLoading()) return null;
        return aipLabel2AppLabel(_policyManager.listSensitivityLabels());
    }
    public List<AipTemplate> getTemplates() {
        if (!checkLoading()) return null;

        try {
            List<AipTemplate> result = new ArrayList<>();
            var templates = _protectionManager.getTemplates();
            if (templates == null) return new ArrayList<>();
            templates.forEach(template -> {
                var aipTemplate = Utilities.templateToAip(template);
                if (aipTemplate != null) {
                    result.add(aipTemplate);
                }
            });
            return result;
        }
        catch (Exception ex) {
            setError(33, "AipFileManager::GetTemplates Failed.", ex.getMessage());
            return new ArrayList<>();
        }
    }

    public AipFileInfo getFileInfo(String fileName) {
        if (!checkLoading()) {
            return new AipFileInfo(10, "AIP 라이브러리가 초기화 되지 않았습니다.");
        }
        AipFileInfo fileInfo = _fileManager.getFileInfo(fileName);
        if (fileInfo == null) {
            setError(_fileManager.getLastErrNo(), "AipFileManager::GetFileInfo Failed.", _fileManager.getLastErrMsg());
            return new AipFileInfo(11, _fileManager.getLastErrMsg());
        }
        return fileInfo;
    }
    public AipFileInfo getFileInfo(IStream fileStream, String outputFileName) {
        if (!checkLoading()) {
            return new AipFileInfo(10, "AIP 라이브러리가 초기화 되지 않았습니다.");
        }
        AipFileInfo fileInfo = _fileManager.getFileInfo(fileStream, outputFileName);
        if (fileInfo == null) {
            setError(_fileManager.getLastErrNo(), "AipFileManager::GetFileInfo Failed.", _fileManager.getLastErrMsg());
            return new AipFileInfo(11, _fileManager.getLastErrMsg());
        }
        return fileInfo;
    }

    public AipFileStatus getAipFileStatus(String fileName) {
        try {
            IFileStatus fileStatus = FileHandler.GetFileStatus(fileName, _mipContext);
            return AipFileStatus.builder()
                    .isLabeled(fileStatus.IsLabeled())
                    .isProtected(fileStatus.IsProtected())
                    .containsProtectedObjects(fileStatus.ContainsProtectedObjects())
                    .build();
        }
        catch (Exception ex) {
            setError(81, "AipFileManager::GetAipFileStatus Failed.", ex.getMessage());
        }
        return null;
    }


    public SetFileInfo setLabel(String fileName, String actualFileName, String email, String labelId, String templateId, String comments) {
        // 레이블 및 템플릿 정보 가져오기
        if (Objects.equals(comments, "")) {
            comments = "SetLabel";
        }
        return _fileManager.setLabel(fileName, actualFileName, email, labelId, templateId, comments);
    }
    public SetFileInfo setLabel(IStream fileStream, String actualFileName, String email, String labelId, String templateId, String comments) {
        if (Objects.equals(comments, "")) {
            comments = "SetLabel by " + email;
        }
        // 레이블 및 템플릿 정보 가져오기
        return _fileManager.setLabel(fileStream, actualFileName, email, labelId, templateId, comments);
    }

    public SetFileInfo deleteLabel(String fileName, String actualFileName, String email, String comments, boolean isDelProtection) {
        if (Objects.equals(comments, "")) {
            comments = "Delete Label by " + email;
        }
        return _fileManager.deleteLabel(fileName, actualFileName, email, comments, isDelProtection);
    }
    public SetFileInfo deleteLabel(IStream fileStream, String actualFileName, String email, String comments, boolean isDelProtection) {
        if (Objects.equals(comments, "")) {
            comments = "Delete Label by " + email;
        }
        return _fileManager.deleteLabel(fileStream, actualFileName, email, comments, isDelProtection);
    }

    public SetFileInfo setProtection(String fileName, String actualFileName, String email, String templateId, String comments) {
        if (Objects.equals(comments, "")) {
            comments = "SetProtection by " + email;
        }
        return _fileManager.setProtection(fileName, actualFileName, email, templateId, comments);
    }
    public SetFileInfo setProtection(IStream fileStream, String actualFileName, String email, String templateId, String comments) {
        if (Objects.equals(comments, "")) {
            comments = "SetProtection by " + email;
        }
        return _fileManager.setProtection(fileStream, actualFileName, email, templateId, comments);
    }

    public SetFileInfo deleteProtection(String fileName, String actualFileName, String email, String comments) {
        if (Objects.equals(comments, "")) {
            comments = "Delete Protection by " + email;
        }
        return _fileManager.removeProtection(fileName, actualFileName, email, comments);
    }
    public SetFileInfo deleteProtection(IStream fileStream, String actualFileName, String email, String comments) {
        if (Objects.equals(comments, "")) {
            comments = "Delete Protection by " + email;
        }
        return _fileManager.removeProtection(fileStream, actualFileName, email, comments);
    }


    public boolean isProtected(IStream inputStream, String filePath) {
        IFileStatus status = FileHandler.GetFileStatus(inputStream, filePath, _mipContext);
        return status.IsProtected();
    }
    public boolean isLabeledOrProtected(IStream inputStream, String filePath) {
        IFileStatus status = FileHandler.GetFileStatus(inputStream, filePath, _mipContext);
        return (status.IsLabeled() || status.IsProtected());
    }
    public boolean isProtected(String filePath) {
        IFileStatus status = FileHandler.GetFileStatus(filePath, _mipContext);
        return status.IsProtected();
    }
    public boolean isLabeledOrProtected(String filePath) {
        IFileStatus status = FileHandler.GetFileStatus(filePath, _mipContext);
        return (status.IsLabeled() || status.IsProtected());
    }
}
