package com.brilliance.isc.common.component;

import com.brilliance.isc.bo.Dia;
import com.brilliance.isc.bo.Ers;
import com.brilliance.isc.bo.Smh;
import com.brilliance.isc.bo.Spt;
import com.brilliance.isc.common.context.AppEnv;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.sysmod.SysmodService;
import com.brilliance.isc.common.transaction.vo.BaseTransactionVo;
import com.brilliance.isc.common.util.StringUtils;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.constant.ErrorCode;
import com.brilliance.isc.exception.SSTFException;
import com.brilliance.isc.mda.dao.DiaMapper;
import com.brilliance.isc.mda.dao.ErsMapper;
import com.brilliance.isc.mda.dao.SmhMapper;
import com.brilliance.isc.mda.dao.SptMapper;
import com.brilliance.mda.runtime.mda.IStream;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

@Component
public class SptDataComponent {

    private static Logger log = LoggerFactory.getLogger(SptDataComponent.class);

    @Autowired
    private DiaMapper diaMapper;

    @Autowired
    private SysmodService sysmodService;

    @Autowired
    private SmhMapper smhMapper;

    @Autowired
    private SptMapper sptMapper;

    @Autowired
    private ErsMapper ersMapper;

    @Autowired
    private AppEnv appEnv;

    @Autowired
    private DyncDaoService dyncDaoService;

    /**
     * 加载spt数据
     * 1.从交易对象中拿
     * 2.从SettleContext中拿
     * @param bo
     * @return-D60-D61-DZKLSQ-DZXGSQ-
     */
    public Spt loadSpt(BaseTransactionVo bo) {
        Spt spt = null;
        if (bo == null) {
            //试算过程中需要用到spt数据
            spt = SettleContext.getUserSession().getSpt();
        } else {
            //直接从BaseTransactionVo拿到spt数据
            spt = bo.getSpt();
        }
        return spt;
    }

    public Smh loadSmh(BaseTransactionVo bo) {
        Spt spt = loadSpt(bo);
        if (spt != null) {
            if (StringUtils.isNotEmpty(spt.getSmhinr())) {
                Smh vo = new Smh();
                vo.setInr(spt.getSmhinr());
                return smhMapper.selectByPrimaryKey(vo);
            } else {
                Spt vo = new Spt();
                vo.setInr(spt.getInr());
                Spt spt1 = sptMapper.selectByPrimaryKey(vo);
                if (spt1 != null) {
                    Smh smhVo = new Smh();
                    smhVo.setInr(spt1.getSmhinr());
                    return smhMapper.selectByPrimaryKey(smhVo);
                } else {
                    return null;
                }
            }
        } else {
            return null;
        }
    }

    public Smh loadSmh(BaseTransactionVo bo, String dir, String cortyp) {
        Spt spt = loadSpt(bo);
        if (spt != null) {
            if (StringUtils.isNotEmpty(spt.getSmhinr())) {
                Smh vo = new Smh();
                vo.setInr(spt.getSmhinr());
                vo.setDir(dir);
                vo.setCortyp(cortyp);
                return smhMapper.selectByPrimaryKey(vo);
            } else {
                Spt vo = new Spt();
                vo.setInr(spt.getInr());
                Spt spt1 = sptMapper.selectByPrimaryKey(vo);
                if (spt1 != null) {
                    Smh smhVo = new Smh();
                    smhVo.setDir(dir);
                    smhVo.setCortyp(cortyp);
                    smhVo.setInr(spt1.getSmhinr());
                    return smhMapper.selectByPrimaryKey(smhVo);
                } else {
                    return null;
                }
            }
        } else {
            return null;
        }
    }

    public Ers loadErs(BaseTransactionVo bo) {
        Smh smh = loadSmh(bo);
        if (smh != null) {
            Ers ers = ersMapper.getErsBySmhinr(smh.getInr());
            return ers;
        } else {
            return null;
        }
    }

    public Ers loadErs(BaseTransactionVo bo, String dir, String cortyp) {
        Smh smh = loadSmh(bo, dir, cortyp);
        if (smh != null) {
            Ers vo = new Ers();
            vo.setSmhinr(smh.getInr());
            List<Ers> ersList = ersMapper.selectByWhere(vo);
            if (CollectionUtils.isNotEmpty(ersList)) {
                return ersList.get(0);
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 根据spt 获取 doapic数据
     * 代码出处 Trnmod.init1000()
     * @param bo
     * @return
     */
    public Dia getDiapic(BaseTransactionVo bo) {
        Spt spt = loadSpt(bo);
        if (spt == null) {
            log.warn("没有获取到Spt数据");
            return null;
        }
        if ("DIA".equals(spt.getCreobjtyp()) && StringUtils.isNotEmpty(spt.getInr())) {
            Dia dia = new Dia();
            dia.setInr(spt.getCreobjinr());
            return diaMapper.selectByPrimaryKey(dia);
        }
        return null;
    }

    /**
     * 合并SptData至dbBo
     * dbBo一定是从数据库读取的或者直接new的
     * @param sptBo
     * @param dbBo
     * @return
     */
    public void mergeSptAndContractData(BaseTransactionVo sptBo,BaseTransactionVo dbBo){
        Spt spt = sptBo.getSpt();
        //从文件中获取Key，
        //TODO 优化下，避免两次IO
        Map<String,Object> sptDataMap = sysmodService.sptLoadData(Map.class, spt.getInr());
        sptDataMap.remove("spt");
        mergeSptAndContractData(sptBo,dbBo,sptDataMap);
        //更新SPT
        dbBo.setSpt(sptBo.getSpt());
    }


    /**
     * 合并SptData至dbBo
     * dbBo一定是从数据库读取的或者直接new的
     * @param srcBo
     * @param destBo
     * @param sptDataMap
     * @return
     */
    public void mergeSptAndContractData(Object srcBo, Object destBo, Map<String,Object> sptDataMap){
        sptDataMap.entrySet().forEach(stringObjectEntry -> {
            String key = stringObjectEntry.getKey();
            Object val = stringObjectEntry.getValue();
            if(val instanceof Map){
                //递归
                Object[] twoObjs = collectFieldValue(srcBo,destBo,key);
                if(twoObjs != null && twoObjs.length == 2){
                    mergeSptAndContractData(twoObjs[0],twoObjs[1],(Map)val);
                }
            }else{
                copyFieldValue(srcBo,destBo,key);
            }
        });
    }
    private void copyFieldValue(Object src,Object dest,String fieldName){
        try {
            Field field = src.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            Object val =field.get(src);
            field.set(dest,val);
        }catch (Exception e){
            log.warn("合并SPT时字段复制发生错误：{}",e);
        }
    }

    private Object[] collectFieldValue(Object src,Object dest,String fieldName){

        try {
            Field field = src.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            if(field.getType().isAssignableFrom(Logger.class)){
                return null;
            }else if(field.getType().isAssignableFrom(IStream.class)){
                field.set(dest,field.get(src));
                return null;
            }
            Object val =field.get(src);
            Object val2 = field.get(dest);
            if(val2 == null){
                //如果为空则辅助构建
                val2 = field.getType().newInstance();
                field.set(dest,val2);
            }
            return new Object[]{val,val2};
        }catch (Exception e){
            log.warn("合并SPT时字段复制成员对象时发生错误：{}",e);
        }
        return null;
    }

    /**
     * INC - swift来报
     * YPT - 云平台
     * EJS - E结算
     * HNH - 汇款行内划转
     * 需要加载读取spt文件
     * @param sptSta
     * @return
     */
    public boolean needMergeSptData(String sptSta){
        switch (sptSta){
            case "INC":
            case "YPT":
            case "EJS":
            case "HNH":
            case "TRA":
                return true;
            default:
                return false;
        }
    }

    /**
     * 是否需要走init加载来报数据
     * CIPS - 从cnd cnn中获取
     * FMT - 境内外币 从atd中获取
     * @param spt
     * @return
     */
    public boolean hasSptButNoSptFile(Spt spt){
        String sptSta = spt.getSta();
        if (sptSta == null) {
            return false;
        }
        boolean flag = false;
        switch (sptSta){
            //境内外币
            case "FMT":
            //大额支付系统
            case "HVP":
            case "HVQ":
            case "HVR":
            //小额支付系统
            case "BEP":
            case "BEQ":
            case "BES":
            //CIPS
            case "CIU":
            case "CIV":
            case "CIW":
            //批量汇款
            case "BAT":
            //电商6701、6801、6901
            case "ECM":
                flag = true;
                break;
            default:
                flag = false;
                break;
        }
        if (flag && !sysmodService.existSptFile("delete", spt.getInr() + ".bak")) {
            //来报数据但是没有spt文件
            return true;
        }
         return false;
        }
    
    public boolean hasSptData(String sptSta){
        switch (sptSta){
            case "INC":
            case "YPT":
            case "EJS":
                return true;
            default:
                return false;
        }
    }

    public boolean needMergeSptData(BaseTransactionVo baseTransactionVo){
        if(baseTransactionVo.getSpt() == null){
            return false;
        }
        String sptSta = baseTransactionVo.getSpt().getSta();
        if(sptSta == null){
            sptSta = "";
        }
        switch (sptSta){
            case "INC":
            case "YPT":
            case "EJS":
            case "TRA":
                return true;
            default:
                return false;
        }
    }

    public boolean isCnyPayment(String sptSta){
        switch (sptSta){
            //大额支付系统
            case "HVP":
            case "HVQ":
            case "HVR":
            //小额支付系统
            case "BEP":
            case "BEQ":
            case "BES":
            //CIPS
            case "CIU":
            case "CIV":
            case "CIW":
                return true;
            default:
                return false;
        }
    }

    public boolean isCipsPayment(String sptSta){
        switch (sptSta){
                //CIPS
            case "CIU":
            case "CIV":
            case "CIW":
                return true;
            default:
                return false;
        }
    }

    public boolean isXxpsPayment(String sptSta){
        switch (sptSta){
            //大额支付系统 hvps
            case "HVP":
            case "TRA":
            case "HVQ":
            case "HVR":
                //小额支付系统 beps
            case "BEP":
            case "BEQ":
            case "BES":
                return true;            
            default:
                return false;
        }
    }

    public boolean isVerMeet(Object entity){
        String dbVer = getDBVer(entity);
        if (MdaUtils.isEmpty(dbVer)) {
            return true;
        }
        String ver = Utils.getFieldValue(entity,"ver","");
        if(MdaUtils.isEmpty(ver)){
            log.warn("当前实体ver为空，无法读取版本号");
            return false;
        }
        //正常情况下，dbVer应该与ver一致
        if(MdaUtils.compareTo(ver,dbVer) >= 0 ){
            return true;
        }
        return false;
    }

    public String getDBVer(Object entity){
        String table = Utils.getBoType(entity);
        String inr = Utils.getFieldValue(entity,"inr","");
        if(MdaUtils.isEmpty(inr)){
            //
            throw new SSTFException(ErrorCode.BIZ_COMMON_ERROR,"当前实体inr为空，无法读取版本号");
        }
        //业务主表、副表都存有ver，动态获取该版本号
        String dbVer = dyncDaoService.dyncReadFieldByInr(table,inr,"ver");
        return dbVer;
    }
}
