package com.brilliance.isc.common.transaction.newcheck;

import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.exception.ValidateException;
import com.brilliance.isc.common.util.I18nUtil;
import com.brilliance.isc.common.vo.AbstractCommonVo;
import com.brilliance.isc.utils.ValidatorUtils;
import com.brilliance.isc.vo.WarnVo;
import com.brilliance.isc.warn.WarnService;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public abstract class AbstractModuleValidator<T extends AbstractCommonVo> implements IModuleValidator<T> {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private ThreadLocal<Object> parent = ThreadLocal.withInitial(() -> new Object());
    private Map<String, List<IValidator<T, ValidResult>>> validationMap = new HashMap<>();
    //warningMap必须是有序的 交易会计算warning列表的mac值
    private Map<String, Map<String, List<IValidator<T, WarningResult>>>> warningMap = new LinkedHashMap<>();

    @Autowired
    private WarnService warnService;

    public void register() {
        for (Method method : this.getClass().getDeclaredMethods()) {
            Validate validate = method.getAnnotation(Validate.class);
            if (validate != null && "Y".equals(validate.enable())) {
                //如果标明了@validate且enable是Y，表示这个方法是验证方法
                String path = validate.path();
                doRegister(path, (T) -> (ValidResult) method.invoke(this, T));
            }
            Warning warning = method.getAnnotation(Warning.class);
            if (warning != null && "Y".equals(warning.enable())) {
                //如果标明了@warning且enable是Y，表示这个方法是警告方法
                String path = warning.path();
                String level = warning.level();
                doRegister(path, level, (T) -> (WarningResult) method.invoke(this, T));
            }
        }
    }

    private void doRegister(String fieldFullPath, IValidator<T, ValidResult> validator) {
        List<IValidator<T, ValidResult>> list = validationMap.computeIfAbsent(fieldFullPath, (k) -> new ArrayList<>());
        list.add(validator);
    }

    private void doRegister(String fieldFullPath, String level, IValidator<T, WarningResult> validator) {
        Map<String, List<IValidator<T, WarningResult>>> map = warningMap.computeIfAbsent(fieldFullPath, (k) -> new LinkedHashMap<>());
        List<IValidator<T, WarningResult>> list = map.computeIfAbsent(level, (k) -> new ArrayList<>());
        list.add(validator);
    }

    public void registerParent(Object object) {
        parent.set(object);
    }

    public Object getParent() {
        return parent.get();
    }

    public void removeTl() {
        parent.remove();
    }

    @Override
    public Map<String, String> validate(T vo) {
        Map<String, String> fieldErrors = new HashMap<>();
        for (Map.Entry<String, List<IValidator<T, ValidResult>>> entry : validationMap.entrySet()) {
            //获取验证字段的全路径 来自@Validate的path
            String fieldFullPath = entry.getKey();
            //获取验证方法集合并执行，来自register()方法
            List<IValidator<T, ValidResult>> validators = entry.getValue();
            for (IValidator<T, ValidResult> validator : validators) {
                try {
                    ValidResult result = validator.validate(vo);
                    //如果结果是false，则表示校验不通过
                    if (result != null && !result.isValid()) {
                        fieldErrors.put(fieldFullPath, result.getError());
                    }
                } catch (InvocationTargetException e) {
                    handleInvocationTargetException(e, fieldFullPath);
                } catch (Exception e) {
                    logger.error("校验时发生异常:{}", e);
                    throw new CommonServiceException(this.getClass().getSimpleName() + " Validate Field{" + fieldFullPath + "} Occured Exception: " + e.getMessage());
                }
            }
        }
        for (String fieldFullPath : warningMap.keySet()) {
            //获取验证字段的全路径 来自@Warning的path
            Map<String, List<IValidator<T, WarningResult>>> maps = warningMap.get(fieldFullPath);
            for (Map.Entry<String, List<IValidator<T, WarningResult>>> entry : maps.entrySet()) {
                //获取警告级别
                String level = entry.getKey();
                //获取验证方法集合并执行，来自register()方法
                List<IValidator<T, WarningResult>> validators = entry.getValue();
                for (IValidator<T, WarningResult> validator : validators) {
                    try {
                        WarningResult result = validator.validate(vo);
                        warnService.registerWarn(level, fieldFullPath, result.getSubid(), WarnVo.SOURCE_BACK, result.getMessage(),result.getVal());
                    } catch (InvocationTargetException e) {
                        handleInvocationTargetException(e, fieldFullPath);
                    } catch (Exception e) {
                        logger.error("获取警告信息时发生异常:{}", e);
                        throw new CommonServiceException(this.getClass().getSimpleName() + " Warning Field{" + fieldFullPath + "} Occured Exception: " + e.getMessage());
                    }
                }
            }
        }
        return fieldErrors;
    }

    @Override
    public Map<String, String> validate(T vo, int index) {
        Map<String, String> fieldErrors = new HashMap<>();
        for (Map.Entry<String, List<IValidator<T, ValidResult>>> entry : validationMap.entrySet()) {
            //获取验证字段的全路径 来自@Validate的path
            String fieldFullPath = entry.getKey();
            //获取验证方法集合并执行，来自register()方法
            List<IValidator<T, ValidResult>> validators = entry.getValue();
            for (IValidator<T, ValidResult> validator : validators) {
                try {
                    ValidResult result = validator.validate(vo);
                    //如果结果是false，则表示校验不通过
                    if (result != null && !result.isValid()) {
                        fieldErrors.put(String.format(fieldFullPath, index), result.getError());
                    }
                } catch (InvocationTargetException e) {
                    handleInvocationTargetException(e, fieldFullPath);
                } catch (Exception e) {
                    logger.error("校验时发生异常:{}",e);
                    throw new CommonServiceException(this.getClass().getSimpleName() + " Validate Field{" + fieldFullPath + "} Occured Exception: " + e.getMessage());
                }
            }
        }
        for (String fieldFullPath : warningMap.keySet()) {
            //获取验证字段的全路径 来自@Warning的path
            Map<String, List<IValidator<T, WarningResult>>> maps = warningMap.get(fieldFullPath);
            for (Map.Entry<String, List<IValidator<T, WarningResult>>> entry : maps.entrySet()) {
                //获取警告级别
                String level = entry.getKey();
                //获取验证方法集合并执行，来自register()方法
                List<IValidator<T, WarningResult>> validators = entry.getValue();
                for (IValidator<T, WarningResult> validator : validators) {
                    try {
                        WarningResult result = validator.validate(vo);
                        warnService.registerWarn(level, String.format(fieldFullPath, index), result.getSubid(), WarnVo.SOURCE_BACK, result.getMessage(),result.getVal());
                    } catch (InvocationTargetException e) {
                        handleInvocationTargetException(e, fieldFullPath);
                    } catch (Exception e) {
                        logger.error("获取警告信息时发生异常:{}",e);
                        throw new CommonServiceException(this.getClass().getSimpleName() + " Warning Field{" + fieldFullPath + "} Occured Exception: " + e.getMessage());
                    }
                }
            }
        }
        return fieldErrors;
    }

    private void handleInvocationTargetException(InvocationTargetException e, String fieldFullPath) {
        logger.error("获取警告信息时发生异常:{}", e.getTargetException());
        if(e.getTargetException() !=  null && e.getTargetException() instanceof ValidateException){
            throw new CommonServiceException(e.getTargetException().getMessage());
        }else{
            throw new CommonServiceException(this.getClass().getSimpleName() + " Warning Field{" + fieldFullPath + "} Occured Exception: " + e.getTargetException().getMessage());
        }
    }

    /**
     * key获取国际化message
     *
     * @param key
     * @param args
     * @return
     */
    protected String getMessage(String key, String... args) {
        return I18nUtil.getMessage(key, SettleContext.getLocale(), args);
    }

    protected String getI18NString(String moduleName, String key) {
        return I18nUtil.getI18NString(moduleName, key, SettleContext.getLocale());
    }

    /**
     * 非空统一方法
     */
    protected ValidResult errorMandatory() {
        return ValidResult.build(false, getMessage("0002", null));
    }

    /**
     * 判断是否包含 characterZ 字符集
     * 默认该值不能包含*号，如果不想校验*号，请使用 characterZ(txt,false)
     * @param txt
     * @return
     */
    protected ValidResult characterZ(String txt) {
        if (ValidatorUtils.hasChinese(txt)) {
            return ValidResult.build(false, getMessage("0061", null));
        } else {
            if (ValidatorUtils.characterZ(txt)) {
                return ValidResult.build(false, getMessage("0006", null));
            }
        }
        return checkTxmBlock(txt);
    }

    /**
     * 判断是否包含 characterZ 字符集
     * 提供一个是否要检查条款项的选项，如果为true，则会检查是否带*，如果为false，则不会校验
     * @param txt
     * @return
     */
    protected ValidResult characterZ(String txt,boolean isTxmBlock) {
        if (ValidatorUtils.hasChinese(txt)) {
            return ValidResult.build(false, getMessage("0061", null));
        } else {
            if (ValidatorUtils.characterZ(txt)) {
                return ValidResult.build(false, getMessage("0006", null));
            }
        }
        if(isTxmBlock){
            return checkTxmBlock(txt);
        }
        return null;
    }

    /**
     * 判断是否包含特殊字符集 characterX<br>
     * 默认该值不能包含*号，如果不想校验*号，请使用 characterX(txt,false)
     *
     * @param txt
     * @return
     */
    protected ValidResult characterX(String txt) {
        if (ValidatorUtils.hasChinese(txt)) {
            return ValidResult.build(false, getMessage("0061", null));
        } else {
            if (ValidatorUtils.characterX(txt)) {
                return ValidResult.build(false, getMessage("0066", null));
            }
        }
        return checkTxmBlock(txt);
    }

    /**
     * 判断是否包含特殊字符集 characterX<br>
     * 提供一个是否要检查条款项的选项，如果为true，则会检查是否带*，如果为false，则不会校验
     *
     * @param txt
     * @return
     */
    protected ValidResult characterX(String txt, boolean isTxmBlock) {
        if (ValidatorUtils.hasChinese(txt)) {
            return ValidResult.build(false, getMessage("0061", null));
        } else {
            if (ValidatorUtils.characterX(txt)) {
                return ValidResult.build(false, getMessage("0066", null));
            }
        }
        if(isTxmBlock){
            return checkTxmBlock(txt);
        }
        return null;
    }

    /**
     * 判断是否包含特殊字符 character<br>
     * 提供一个是否要检查条款项的选项，如果为true，则会检查是否带*，如果为false，则不会校验
     *
     * @param txt
     * @param isTxmBlock 是否是条款输入项
     * @return
     */
    protected ValidResult character(String txt,boolean isTxmBlock) {
        if (ValidatorUtils.hasChinese(txt)) {
            return ValidResult.build(false, getMessage("0061", null));
        } else {
            if (ValidatorUtils.character(txt)) {
                return ValidResult.build(false, getMessage("0237", null));
            }
        }
        if(isTxmBlock){
            return checkTxmBlock(txt);
        }
        return null;
    }

    /**
     * 判断是否包含特殊字符 character<br>
     * 默认该值不能包含*号，如果不想校验*号，请使用 character(txt,false)
     *
     * @param txt
     * @return
     */
    protected ValidResult character(String txt) {
        if (ValidatorUtils.hasChinese(txt)) {
            return ValidResult.build(false, getMessage("0061", null));
        } else {
            if (ValidatorUtils.character(txt)) {
                return ValidResult.build(false, getMessage("0237", null));
            }
        }
        return checkTxmBlock(txt);
    }

    /**
     * check TXMBLOCK
     * #! Set error, if block contains an Asterisk and is enabled
     *
     *  Service routine to display an error message if passed text holds a `*`-character.
     *  ArgBlk holds the textblock to be checked for *-character
     *  2018swift升级，将“*”改成"}"
     * @param txt
     * @return
     */
    protected ValidResult checkTxmBlock(String txt){
        if(!MdaUtils.isEmpty(txt) && txt.contains("*")){
            return ValidResult.build(false, "The block contains character \'*\'.\n Please delete the character or replace it with a valid text.");
        }
        return null;
    }
}
