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

import com.brilliance.isc.common.cache.atpbch.AtpBchCacheService;
import com.brilliance.isc.common.component.PtsptaToolComponent;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.context.SpringEnvContext;
import com.brilliance.isc.common.doc.ITransactionDocSet;
import com.brilliance.isc.common.transaction.newcheck.*;
import com.brilliance.isc.common.trndoc.vo.DoceotVo;
import com.brilliance.isc.mda.dao.PublicMapper;
import com.brilliance.mda.runtime.mda.IStream;
import com.brilliance.mda.runtime.mda.impl.StreamImpl;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.brilliance.mda.runtime.mda.util.Streams;
import com.brilliance.mda.runtime.mda.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;


@Component
public class DoceotValidator extends AbstractModuleValidator<DoceotVo> {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private PtsptaToolComponent ptsptaToolComponent;

    @Autowired
    private PublicMapper publicMapper;

    @Autowired
    private AtpBchCacheService atpBchCacheService;


    @Validate(path="docpan.doceot.%s.cortyp", enable = "N")
    public ValidResult checkCortyp(DoceotVo doceotVo){
        if (isSWTRequired(doceotVo) && !"SWT".equalsIgnoreCase(doceotVo.getCortyp())) {
            return ValidResult.build(false, getMessage("0180", null));
        }
        return null;
    }

    /**
     *   source:doceot.0039.script
     */
    @Validate(path = "docpan.doceot.%s.adrfax")
    public ValidResult checkAdrfax(DoceotVo doceotVo){
        if(!MdaUtils.isEmpty(doceotVo.getId())) {
            if(MdaUtils.compareTo(doceotVo.getDelflg()," ") == 0) {
                if(MdaUtils.compareTo(doceotVo.getCortyp(),"FAX") == 0
                        && MdaUtils.isEmpty(doceotVo.getAdrfax())) {
                    return ValidResult.build(false, "Missing fax number");
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0040.script
     */
    @Validate(path = "docpan.doceot.%s.adreml")
    public ValidResult checkAdreml(DoceotVo doceotVo){
        if( MdaUtils.compareTo(doceotVo.getLev(),"5") != 0 ) {
            // HVB
            if( ! MdaUtils.isEmpty(doceotVo.getId()) ) {
                if( MdaUtils.compareTo(doceotVo.getDelflg()," ")== 0 ) {
                    if( ( MdaUtils.compareTo(doceotVo.getCortyp(),"EML") == 0
                            || MdaUtils.compareTo(doceotVo.getCortyp(),"EMA") == 0 )
                            && MdaUtils.isEmpty(doceotVo.getAdreml()) ) {
                        return ValidResult.build(false, "Missing e-mail address");
                    }
                }
            }
            //check if synthax of e-mail-address is correct
            if(doceotVo.getAdreml() != null && doceotVo.getAdreml().trim().length() > 0) {
                if (!normalizeEmailAddress(doceotVo.getAdreml())) {
                    return ValidResult.build(false, Strings.formatText("E-Mail-Address is not correct, $1", doceotVo.getAdreml()));
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0041.script
     */
    @Validate(path = "docpan.doceot.%s.adrtid")
    public ValidResult checkAdrtid(DoceotVo doceotVo){
        if(!MdaUtils.isEmpty(doceotVo.getId())) {
            if( MdaUtils.compareTo(doceotVo.getDelflg(), " ")== 0 ) {
                if( MdaUtils.compareTo(doceotVo.getCortyp(),"TCO") == 0
                        && MdaUtils.isEmpty(doceotVo.getAdrtid()) ) {
                    return ValidResult.build(false, "Missing TradeConnect ID");
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0042.script
     */
    @Validate(path = "docpan.doceot.%s.adrbic")
    public ValidResult checkAdrbic(DoceotVo doceotVo){
        if( ! MdaUtils.isEmpty(doceotVo.getId()) ) {
            if( MdaUtils.compareTo(doceotVo.getDelflg()," ")== 0 ) {
                if( MdaUtils.compareTo(doceotVo.getCortyp(),"SWT") == 0
                        && MdaUtils.isEmpty(doceotVo.getAdrbic()) ) {
                    return ValidResult.build(false, "Missing BIC");
                }
                //ctx.absGet(Trnmod.class).getPtsmod().getAdrdef().checkADRBIC ( this.getAdrbic() );
            }
        }
        return null;
    }

    /**
     *   source:doceot.0053.script
     */
    @Validate(path = "docpan.doceot.%s.apf")
    public ValidResult checkApf(DoceotVo doceotVo){
        // even for internal documents a form set must be defined/selected
        // # of originals/copies in this form set might be zero
        if(!MdaUtils.isEmpty(doceotVo.getId())) {
            if( MdaUtils.compareTo(doceotVo.getDelflg()," ")== 0 ) {
                if( MdaUtils.isEmpty(doceotVo.getApf()) ) {
                    return ValidResult.build(false, "Missing form set");
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0055.script
     */
    @Validate(path = "docpan.doceot.%s.adrdtacid")
    public ValidResult checkAdrdtacid(DoceotVo doceotVo){
        if(!MdaUtils.isEmpty(doceotVo.getId())) {
            if( MdaUtils.compareTo(doceotVo.getDelflg()," ")== 0 ) {
                if( MdaUtils.compareTo(doceotVo.getCortyp(),"DTA") == 0
                        && MdaUtils.isEmpty(doceotVo.getAdrdtacid()) ) {
                    return ValidResult.build(false, "Missing address");
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0056.script
     */
    @Validate(path = "docpan.doceot.%s.adrdtecid")
    public ValidResult checkAdrdtecid(DoceotVo doceotVo){
        if(!MdaUtils.isEmpty(doceotVo.getId())) {
            if( MdaUtils.compareTo(doceotVo.getDelflg()," ")== 0 ) {
                if(MdaUtils.compareTo(doceotVo.getCortyp(),"DTE") == 0
                        && MdaUtils.isEmpty(doceotVo.getAdrdtecid())) {
                    return ValidResult.build(false, "Missing address");
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0065.script
     */
    @Validate(path = "docpan.doceot.%s.adrrid")
    public ValidResult checkAdrrid(DoceotVo doceotVo){
        if( ! MdaUtils.isEmpty(doceotVo.getId()) ) {
            if( MdaUtils.compareTo(doceotVo.getDelflg()," ")== 0 ) {
                if( MdaUtils.compareTo(doceotVo.getCortyp(),"BOL") == 0
                        && MdaUtils.isEmpty(doceotVo.getAdrrid()) ) {
                    return ValidResult.build(false, "Missing Bolero RID");
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0066.script
     */
    @Validate(path = "docpan.doceot.%s.roladr")
    public ValidResult checkRoladr(DoceotVo doceotVo){
        if(!MdaUtils.isEmpty(doceotVo.getId())) {
            if(MdaUtils.isEmpty(doceotVo.getRoladr())) {
                return ValidResult.build(false, "No receiver selected");
            }
        }
        if(MdaUtils.compareTo(doceotVo.getRoladr(),"OTH") == 0
                && ! ptsptaToolComponent.ptsIsRolSet(doceotVo.getRcv())) {
            return ValidResult.build(false, "Please select a party of contract or enter address.");
        }
        return null;
    }

    /**
     *   source:doceot.0111.script
     */
    @Validate(path = "docpan.doceot.%s.staflg")
    public ValidResult checkStaflg(DoceotVo doceotVo){
        //>>>ZL: ISS.000010   从501中移植过来---------
        switch( doceotVo.getStaflg() ) {
            case "M":
                if( MdaUtils.compareTo(doceotVo.getCortyp(),"SWT") != 0
                        || ( MdaUtils.compareTo(doceotVo.getCortyp(),"SWT") == 0
                        && MdaUtils.compareTo(doceotVo.getDocsnf(),"SWT999") != 0 ) ) {
                    return ValidResult.build(false, "只有SWIFT的MT999报文适用该状态");
                }
                break;
            case "T":
                if( MdaUtils.compareTo(doceotVo.getCortyp(),"TLX") != 0 ) {
                    return ValidResult.build(false, "只有TELEX报文适用该状态");
                }
                /**  case "B"
                 $pandsc = Trim( PANDSC )
                 $pandsc = Mid( $pandsc, 1, 3 )
                 if $pandsc <> "CMT" then
                 Error( 'LG000174' )
                 endif**/
                break;
        }
        //<<<ZL: ISS.000010  end-------------
        return null;
    }

    /**
     *   source:doceot.0115.script
     */
    @Validate(path = "docpan.doceot.%s.adrbic")
    public ValidResult checkAdrbicN900(DoceotVo doceotVo){
        //增加：收报行SWIFT号第八位不能是"1"的校验 by lwq
        if( ! MdaUtils.isEmpty(doceotVo.getId()) ) {
            if( MdaUtils.compareTo(doceotVo.getDelflg()," ")== 0 ) {
                if( MdaUtils.compareTo(doceotVo.getCortyp(),"SWT") == 0
                        && ! MdaUtils.isEmpty(doceotVo.getAdrbic()) ) {
                    String bic = Strings.trim(doceotVo.getAdrbic());
                    if( MdaUtils.compareTo(Strings.mid(bic,8,1),"1") == 0 ) {
                        return ValidResult.build(false, "收报行SWIFT号第八位不能是1");
                    }
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0119.script
     */
    //@Validate(path = "docpan.doceot.%s.addstr")
    @Validate(path = "docpan.doceot.%s.cortyp")
    public ValidResult checkAddstr(DoceotVo doceotVo){
        if( ! MdaUtils.isEmpty(doceotVo.getAddstr()) ) {
            if( MdaUtils.compareTo(doceotVo.getCortyp(),"SWT") == 0 ) {
                ValidResult validResult = characterZ(doceotVo.getAddstr());
                if (validResult != null) {
                   return ValidResult.build(false, "附言不允许输入中文和中文符号以及全角字符以及\"}[]|~$`^\"");
                }
            }
        }
        return null;
    }

    /**
     *   source:doceot.0120.script
     */
    @Validate(path = "docpan.doceot.%s.tag79z")
    public ValidResult checkTag79z(DoceotVo doceotVo){
        if(!MdaUtils.isEmpty(doceotVo.getTag79z())) {
            if( MdaUtils.compareTo(doceotVo.getCortyp(),"SWT") == 0 ) {
                return character(doceotVo.getTag79z());
            }
        }
        return null;
    }

    /**
     *   source:doceot.0124.script
     */
    @Validate(path = "docpan.doceot.%s.rcv.pts.bankno")
    public ValidResult checkRcvPtsBankno(DoceotVo doceotVo){
        if( MdaUtils.compareTo(doceotVo.getCortyp(),"ELC") == 0 ) {
            if( ! MdaUtils.isEmpty(doceotVo.getRcv().getPts().getBankno()) ) {
                String sql = "SELECT fqzjjg FROM BNL WHERE FQCYJG='" + doceotVo.getRcv().getPts().getBankno() + "' ";
                Map<String, Object> dyncMap = new HashMap<>();
                dyncMap.put("sql", sql);
                Map<String, Object> maps = publicMapper.dyncQueryMap(dyncMap);
                String sender1 = (String)maps.get("fqzjjg");
                sql = "select regsta from PMS where PTCPTBK = '" + sender1 + "' and MSGTYP = '" + doceotVo.getPandsc() + "' and (prmsta<>'0' or prmsta is null) ";
                dyncMap.put("sql", sql);
                maps = publicMapper.dyncQueryMap(dyncMap);
                String regsta = (String)maps.get("regsta");
                if( MdaUtils.compareTo(regsta,"REGT") != 0 ) {
                    return ValidResult.build(false, "该行号没有加入电证系统，不能发送相关报文");
                }
            }
        }
        return null;
    }

    @Warning(path = "docpan.doceot.%s.cortyp")
    public WarningResult warn999(DoceotVo doceotVo){
        if(!"A".equalsIgnoreCase(doceotVo.getAdrbicaut()) && "SWT".equalsIgnoreCase(doceotVo.getCortyp())){
            return WarningResult.build("SUBCHECK999","注意：收报行"+doceotVo.getAdrbic()+"与我行未建立密押关系");
        }
        return WarningResult.buildEmpty("SUBCHECK999");
    }

    public boolean normalizeEmailAddress(String arg) {
        //! extract addr-spec address part of an e-mail address
        // i.e. the part normally enclosed in angle brackets ("<" and ">")
        // display name and comments are removed
        // for definitions refer to RFC 2822, chapter 3.4.
        // if extraction is not possible or arg seems not to contain a correct e-mail address, an error code is set
        arg = Strings.trim(Strings.toLower(arg));
        // remove `mailto:`
        if (MdaUtils.compareTo(Strings.mid(arg, 1, 7), "mailto:") == 0) {
            arg = Strings.trim(Strings.mid(arg, 8));
        }
        // remove quoted parts
        boolean inflg = false;
        for (int i = 1; i <= Strings.len(arg); i++) {
            if (MdaUtils.compareTo(Strings.mid(arg, i, 1), "\"") == 0) {
                if (inflg) {
                    inflg = false;
                } else {
                    inflg = true;
                }
                arg = Strings.mid(arg, 1, i - 1) + Strings.mid(arg, i + 1);
            } else {
                if (inflg) {
                    arg = Strings.mid(arg, 1, i - 1) + Strings.mid(arg, i + 1);
                }
            }
        }
        if (inflg) {
//            ctx.setErrorCode(601,"Unbalanced \"");
//            if(1==1) return;
            return false;
        }
        // remove comments
        inflg = false;
        for (int i = 1; i <= Strings.len(arg); i++) {
            if (MdaUtils.compareTo(Strings.mid(arg, i, 1), "(") == 0) {
                inflg = true;
                arg = Strings.mid(arg, 1, i - 1) + Strings.mid(arg, i + 1);
            } else {
                if (inflg) {
                    if (MdaUtils.compareTo(Strings.mid(arg, i, 1), ")") == 0) {
                        inflg = false;
                    }
                    arg = Strings.mid(arg, 1, i - 1) + Strings.mid(arg, i + 1);
                }
            }
        }
        if (inflg) {
            return false;
        }
        // extract address in <>
        int pos = 0;
        if (Strings.pos(arg, "<") > 0) {
            arg = Strings.mid(arg, Strings.pos(arg, "<") + 1);
            pos = Strings.pos(arg, ">");
            if (pos <= 0) {
                return false;
            }
            arg = Strings.mid(arg, 1, pos - 1);
        }
        // split local part and domain
        pos = Strings.pos(arg, "@");
        if (pos <= 0) {
            return false;
        }
        String local = Strings.mid(arg, 1, pos - 1);
        String domain = Strings.mid(arg, pos + 1);
        if (Strings.pos(domain, "@") > 0) {
            return false;
        }
        // check local part
        int lastpos = 0;
        int localCnt = Strings.len(local);
        // check for last space in $local (i.e. "xx @yyy")
        if (MdaUtils.compareTo(local + "Z", Strings.trim(local) + "Z") != 0) {
            localCnt = localCnt + 1;
        }
        int p = 0;
        for (int i = 1; i <= localCnt; i++) {
            p = Strings.pos("._-0123456789abcdefghijklmnopqrstuvwxyz!//$%&'*+/=?^`{|}~", Strings.mid(local, i, 1));
            if (p <= 0) {
                return false;
            }
            if (lastpos == 1) {
                if (p < 14) {
                    return false;
                }
            }
            lastpos = p;
        }
        if (lastpos == 1) {
            return false;
        }
        // check domain
        lastpos = 0;
        for (int i = 1; i <= Strings.len(domain); i++) {
            p = Strings.pos(".-0123456789abcdefghijklmnopqrstuvwxyz", Strings.mid(domain, i, 1));
            if (p <= 0) {
                return false;
            }
            if (lastpos == 1) {
                if (p < 13) {
                    return false;
                }
            }
            lastpos = p;
        }
        if (lastpos == 1) {
            return false;
        }
        // check the domain for point
        if (Strings.pos(domain, ".") == 0) {
            return false;
        }
        arg = Strings.trim(local) + "@" + Strings.trim(domain);
        return true;
    }

    /**
     *   source:sysmod.0282.script
     */
    public ValidResult character(String address) {
        IStream txtStm = new StreamImpl();
        int num = 0;
        if( ! MdaUtils.isEmpty(address) ) {
            Streams.streamSet(txtStm, address);
            num = Streams.streamCount(txtStm);
        }
        if( num > 0 ) {
            for(int  i = 1;i <= num;i++) {
                String line = Strings.getLine(txtStm,i);
                if( ! MdaUtils.isEmpty(line) ) {
                    for(int  j = 1;j <= Strings.len(line);j++) {
                        int p = Strings.pos("[}|$`^~]",Strings.mid(line,j,1));
                        if( p > 0 ) {
                            return ValidResult.build(false, "This fields is not allowed [}|$`^~]");
                        }
                    }
                }
            }
        }
        return null;
    }

    private boolean isSWTRequired(DoceotVo doceotVo) {
        String transName = SettleContext.getTransName();
        ITransactionDocSet transactionDocSet = null;
        try {
            transactionDocSet = SpringEnvContext.getBean(atpBchCacheService.getSdTransNameForRegister().toLowerCase() + ".docset");
        } catch (NoSuchBeanDefinitionException e) {
            logger.warn("找不到交易{"+transName+"}报文生成类, 不需要检核条目类型");
        }
        if (transactionDocSet != null) {
            return transactionDocSet.isSWTRequired(doceotVo.getDocnam());
        }
        return false;
    }
}
