package com.engine.salary.encrypt;


import com.engine.common.util.ServiceUtil;
import com.engine.salary.annotation.Encrypt;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import weaver.hrm.User;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class EncryptUtil {
    private static final String NULL = "null";

    private static String ifNull(String value){
        if (NULL.equals(value)) {
            return null;
        }
        return value;
    }

    private SalarySysConfService getSalarySysConfService(User user) {
        return ServiceUtil.getService(SalarySysConfServiceImpl.class, user);
    }

    public <T> T encrypt(T data, Class<T> clazz) {
        if (data == null || clazz == null) {
            return data;
        }
        boolean encryptIsOpen = getSalarySysConfService(null).encryptIsOpen();
        if (!encryptIsOpen) {
            return data;
        }
        try {
            List<Field> fieldList = getFields(clazz);
            if (CollectionUtils.isNotEmpty(fieldList)) {
                for (Field field : fieldList) {
                    field.setAccessible(true);
                    String fieldValue = (String)field.get(data);
                    if (StringUtils.isNotBlank(fieldValue)) {
                        String encryptValue = AESEncryptUtil.encrypt(fieldValue);
                        field.set(data, encryptValue);
                    }
                }
            }
            return data;
        } catch (Exception e) {
            log.error("加密异常", e);
            throw new SalaryRunTimeException("加密异常");
        }
    }

    @NotNull
    private static <T> List<Field> getFields(Class<T> clazz) {
        List<Class<?>> allClasses = new ArrayList<Class<?>>();
        for (Class<?> superClass = clazz;
             superClass != null;
             superClass = superClass.getSuperclass()) {
            if (superClass != Object.class) {
                allClasses.add(superClass);
            }
        }
        List<Field> fieldList =
                allClasses.stream()
                        .map(Class::getDeclaredFields)
                        .flatMap(Arrays::stream)
                        .filter(field -> field.isAnnotationPresent(Encrypt.class)).collect(Collectors.toList());
        return fieldList;
    }

    public <T> List<T> encryptList(List<T> dataList, Class<T> clazz) {
        if (CollectionUtils.isEmpty(dataList) || clazz == null) {
            return dataList;
        }
        boolean encryptIsOpen = getSalarySysConfService(null).encryptIsOpen();
        if (!encryptIsOpen) {
            return dataList;
        }
        try {
            List<Field> fieldList = getFields(clazz);
            if (CollectionUtils.isNotEmpty(fieldList)) {
                for (T data : dataList) {
                    for (Field field : fieldList) {
                        field.setAccessible(true);
                        String fieldValue = (String) field.get(data);
                        if (StringUtils.isNotBlank(fieldValue)) {
                            String encryptValue = AESEncryptUtil.encrypt(fieldValue);
                            field.set(data, encryptValue);
                        }
                    }
                }

            }
            return dataList;
        } catch (Exception e) {
            log.error("批量加密异常", e);
            throw new SalaryRunTimeException("批量加密异常");
        }
    }

    public <T> T decrypt(T data, Class<T> clazz) {
        if (data == null || clazz == null) {
            return data;
        }
        boolean encryptIsOpen = getSalarySysConfService(null).encryptIsOpen();
        if (!encryptIsOpen) {
            return data;
        }
        try {
            List<Field> fieldList = getFields(clazz);
            if (CollectionUtils.isNotEmpty(fieldList)) {
                for (Field field : fieldList) {
                    field.setAccessible(true);
                    String fieldValue = (String) field.get(data);
                    if (StringUtils.isNotBlank(fieldValue)) {
                        String encryptValue = ifNull(AESEncryptUtil.decrypt(fieldValue));
                        field.set(data, encryptValue);
                    }
                }
            }
            return data;
        } catch (Exception e) {
            log.error("解密异常", e);
            throw new SalaryRunTimeException("解密异常");
        }
    }

    public <T> List<T> decryptList(List<T> dataList, Class<T> clazz) {
        if (CollectionUtils.isEmpty(dataList) || clazz == null) {
            return dataList;
        }
        boolean encryptIsOpen = getSalarySysConfService(null).encryptIsOpen();
        if (!encryptIsOpen) {
            return dataList;
        }
        try {
            List<Field> fieldList = getFields(clazz);
            if (CollectionUtils.isNotEmpty(fieldList)) {
                for (T data : dataList) {
                    for (Field field : fieldList) {
                        field.setAccessible(true);
                        String fieldValue = (String) field.get(data);
                        if (StringUtils.isNotBlank(fieldValue)) {
                            String encryptValue = ifNull(AESEncryptUtil.decrypt(fieldValue));
                            field.set(data, encryptValue);
                        }
                    }
                }
            }
            return dataList;
        } catch (Exception e) {
            log.error("批量解密异常", e);
            throw new SalaryRunTimeException("批量解密异常");
        }
    }

}
