package com.brilliance.isc.swift.objmtconvert.model;

import com.brilliance.isc.swift.objmtconvert.result.MtResult;
import com.brilliance.isc.swift.objmtconvert.util.Language;
import com.prowidesoftware.swift.model.SwiftBlock3;
import com.prowidesoftware.swift.model.field.*;
import com.prowidesoftware.swift.model.mt.AbstractMT;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;

import java.io.IOException;
import java.util.*;

import static com.brilliance.isc.swift.objmtconvert.model.busvalidator.ValidatorMethod.*;

/**
 * @author gechengyang
 * @date 2023/3/2
 */
public abstract class AbsMTValidator {

    protected MtResult mtResult = new MtResult();
    private AbstractMT abstractMT = null;
    private String mtStr;
    private String msgType = "";


    public void validatorOfMT103AndMT103REMIT()
    {
       // MtResult mtResult=getMtResult();
        // MT103 mt103= (MT103) this.getAbstractMT();
        //Field32A field32A = mt103.getField32A();
        Field32A field32A = invoke("getField32A");
        String field32Acur="";
        if(field32A!=null){
            field32Acur=field32A.getCurrency();
        }

        //校验规则1.
        //当33B存在时，如果33B和32A的币种不相同，则必须36必须存在；当33B不存在或者33B和32A的币种相同时，36不能存在。
        // Field33B field33B = mt103.getField33B();
        Field33B field33B = invoke("getField33B");

        // Field36 field36=mt103.getField36();
        Field36 field36 = invoke("getField36");
        //33B存在
        if(field33B!=null&& StringUtils.isNotEmpty(field33B.getValue())) {
            String field33Bcur=field33B.getCurrency();
            //两个域的币种不相等，那么 tag 36 必须存在
            if(!field32Acur.equals(field33Bcur)){
                if(isFieldEmpty(field36))
                {
                    mtResult.addDescription(Language.getLanguage("MT103_C1_1", "MT103"));
                }
            }
            //两个域的币种相同，那么 tag 36 不能存在
            else if(!isFieldEmpty(field36)) {
                mtResult.addDescription(Language.getLanguage("MT103_C1_2", "MT103"));
            }
        }
        //33B不存在，那么 tag 36 不能存在
        else if(!isFieldEmpty(field36)) {
            mtResult.addDescription(Language.getLanguage("MT103_C1_3", "MT103"));
        }

        // 校验规则2.
        // 当以下列表既包含发报行BIC的国家地区码又包含收报行的BIC的国家地区码时，33B必须存在。
        // 列表：AD, AT, BE, BG, BV, CH, CY, CZ, DE, DK, ES, EE, FI, FR, GB, GF,
        // GI, GP, GR, HU, IE, IS, IT, LI, LT, LU, LV, MC,MQ, MT, NL, NO, PL,
        // PM, PT, RE, RO, SE, SI, SJ, SK, SM, TF, VA.
        //国家地区码列表。
        final List<String> countryRegionCode = Arrays.asList("AD", "AT", "BE", "BG", "BV", "CH", "CY", "CZ", "DE", "DK", "ES",
                "EE", "FI", "FR", "GB", "GF", "GI", "GP", "GR", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC",
                "MQ", "MT", "NL", "NO", "PL", "PM", "PT", "RE", "RO", "SE", "SI", "SJ", "SK", "SM", "TF", "VA");
        //获取发报行BIC和收报行BIC.
        String sender = getAbstractMT().getSender();
        String receiver = getAbstractMT().getReceiver();
        //获取发报行和收报行国家地区码。
        String senderCountryRegionCode = "";
        String receiverCounterRegionCode = "";
        //检查发报行BIC和收报行BIC是否为空。
        if(sender == null || receiver == null) {
            mtResult.addDescription(Language.getLanguage("MT103_Sender_Receiver_BIC", "MT103"));
        }
        else {
            //从BIC中截取出国家地区码。
            senderCountryRegionCode = sender.substring(4, 6);
            receiverCounterRegionCode = receiver.substring(4, 6);
            //发报行和收报行的国家地区码均属于上述列表，且33B不存在
            if(countryRegionCode.contains(senderCountryRegionCode) &&
                    countryRegionCode.contains(receiverCounterRegionCode) &&
                    isFieldEmpty(field33B)) {
                mtResult.addDescription(Language.getLanguage("MT103_C2", "MT103"));
            }
        }

        // 校验规则3.
        // 当23B的值为SPRI时，23E的值只能选择SDVA, TELB, PHOB, INTC. 当23B的值为SSTD或SPAY时，23E不能存在。
        // 获取23B, 23E的值。
        //Field23B field23B = mt103.getField23B();
        Field23B field23B  = invoke("getField23B");
        //  List<Field23E> field23E = mt103.getField23E();
        List<Field23E> field23E  = invoke("getField23E");
        String[] _23eValues = null;
        //getField23E()的返回值是长度为1的List，实际的23E的值储存在其中的元素的Component中，以\r\n分隔开。
        if(field23E != null && !field23E.isEmpty() && field23E.get(0).getComponent1() != null) {
            //获取23E的实际值，并存储进数组中。
            _23eValues = field23E.get(0).getComponent1().split("\r\n");
        }
        //当23B的值为SPRI时，23E的值只能选择SDVA, TELB, PHOB, INTC。
        if("SPRI".equals(field23B.getValue()) &&_23eValues != null) {
            //判断是否校验通过，避免失败时反复输出提示信息。
            boolean isValidatorC3Failed = false;
            for (String value:_23eValues) {
                if(isValidatorC3Failed) { break; }
                switch (value) {
                    //23E的值通过校验，无事发生。
                    case "SDVA":
                    case "TELB":
                    case "PHOB":
                    case "INTC":
                        break;
                    //出现了SDVA, TELB, PHOB, INTC之外的值。
                    default:
                        mtResult.addDescription(Language.getLanguage("MT103_C3_1", "MT103"));
                        isValidatorC3Failed = true;
                        break;
                }
            }
        }
        //23B的值为SSTD或SPAY时，23E不能存在。
        else if("SSTD".equals(field23B.getValue()) || "SPAY".equals(field23B.getValue())) {
            if(_23eValues != null) {
                mtResult.addDescription(Language.getLanguage("MT103_C3_2", "MT103"));
            }
        }
        //校验规则4.
        //当23B的值为SPRI, SSTD, SPAY的其中一个时，53a域不能选择53D。
        switch (field23B.getValue()) {
            case "SPRI":
            case "SSTD":
            case "SPAY":
                Field53D field53D  = invoke("getField53D");
                if(!isFieldEmpty(field53D)) {
                    mtResult.addDescription(Language.getLanguage("MT103_C4", "MT103"));
                }
                break;
            default:
                break;
        }
        //校验规则5.
        //23B的值为SPRI, SSTD, SPAY时，53B必须填写Party Identifier.
        //  Field53B field53B = mt103.getField53B();
        Field53B field53B  = invoke("getField53B");
        switch (field23B.getValue()) {
            case "SPRI":
            case "SSTD":
            case "SPAY":
                // Field53B的Component列表中各元素的值与Info, Party Identifier, Location的对应关系会随着这三项的填写情况而发生改变。
                // 三项都填写时，Component2为Info, Component3为Party Identifier, Location的值没有输入Component中。
                // 不填写Party Identifier时，Component2为Info, Component3为Location.
                // 不填写Location会报错空指针。
                // 不填写Info时，Component2为Party Identifier, Component3为Location.
                // 只填写Info或Party Identifier会报错空指针。显然此时也没有填写Location。
                // 只填写Location时，Component3为Location, Component2为空。
                // 不论哪种情况，Component1都为空，Components列表的长度都为3。

                // 由于Info属于Party Identifier的一部分，可以通过Component2是否为空来判断是否填写了Party Identifier.
                // 当既没有填写Info也没有填写Party Identifier时，Component2为空。
                // 只要填写了其中一个，Component2就不为空。
                if(!isFieldEmpty(field53B)){
                    //Component2.
                    String field53BComponent2 = field53B.getComponent2();
                    // 判断Component2是否为空。
                    if (StringUtils.isEmpty(field53BComponent2)) {
                        mtResult.addDescription(Language.getLanguage("MT103_C5", "MT103"));
                    }
                }
                break;
            default:
                break;
        }
        //校验规则6.
        //23B的值为SPRI, SSTD, SPAY时，不能使用54B和54D.
        switch (field23B.getValue()) {
            case "SPRI":
            case "SSTD":
            case "SPAY":
                Field54B field54B=invoke("getField54B");
                Field54D field54D=invoke("getField54D");

                if(!isFieldEmpty(field54B) || !isFieldEmpty(field54D)) {
                    mtResult.addDescription(Language.getLanguage("MT103_C6", "MT103"));
                }
                break;
            default:
                break;
        }
        //校验规则7.
        //55a存在时，53a和54a不能为空。
        //存在55a
        if(!isFieldListAllEmpty(new ArrayList<Field>() {{
//            add(mt103.getField55A());
//            add(mt103.getField55B());
//            add(mt103.getField55D());

            add(invoke("getField55A"));
            add(invoke("getField55B"));
            add(invoke("getField55D"));

        }})) {
            //53a和54a不能为空。
            if(isFieldListAllEmpty(new ArrayList<Field>() {{
//                add(mt103.getField53A());
//                add(mt103.getField53B());
//                add(mt103.getField53D());
                add(invoke("getField53A"));
                add(invoke("getField53B"));
                add(invoke("getField53D"));

            }}) || isFieldListAllEmpty(new ArrayList<Field>() {{
//                add(mt103.getField54A());
//                add(mt103.getField54B());
//                add(mt103.getField54D());

                add(invoke("getField54A"));
                add(invoke("getField54B"));
                add(invoke("getField54D"));

            }}) ) {
                mtResult.addDescription(Language.getLanguage("MT103_C7", "MT103"));
            }
        }
        //校验规则8.
        //23B的值为SPRI, SSTD, SPAY时，55a域必须使用55A.
        switch (field23B.getValue()) {
            case "SPRI":
            case "SSTD":
            case "SPAY":
                if(!isFieldListAllEmpty(new ArrayList<Field>() {{
                    add(invoke("getField55B"));
                    add(invoke("getField55D"));
                }})) {
                    mtResult.addDescription(Language.getLanguage("MT103_C8", "MT103"));
                }
                break;
            default:
                break;
        }
        //校验规则9.
        //56a存在时，57a不能为空。
        //判断56a是否存在。
        if(!isFieldListAllEmpty(new ArrayList<Field>() {{

//            add(mt103.getField56A());
//            add(mt103.getField56C());
//            add(mt103.getField56D());

            add(invoke("getField56A"));
            add(invoke("getField56C"));
            add(invoke("getField56D"));

        }})) {
            //判断57a是否存在。
            if(isFieldListAllEmpty(new ArrayList<Field>() {{

//                add(mt103.getField57A());
//                add(mt103.getField57B());
//                add(mt103.getField57C());
//                add(mt103.getField57D());

                add(invoke("getField57A"));
                add(invoke("getField57B"));
                add(invoke("getField57C"));
                add(invoke("getField57D"));

            }})) {
                mtResult.addDescription(Language.getLanguage("MT103_C9", "MT103"));
            }
        }
        //校验规则10.
        //23B的值为SPRI时，56a域不能存在。
        if ("SPRI".equals(field23B.getValue())) {
            if(!isFieldListAllEmpty(new ArrayList<Field>() {{

//                add(mt103.getField56A());
//                add(mt103.getField56C());
//                add(mt103.getField56D());

                add(invoke("getField56A"));
                add(invoke("getField56C"));
                add(invoke("getField56D"));
            }})) {
                mtResult.addDescription(Language.getLanguage("MT103_C10_1", "MT103"));
            }
        }
        //23B的值为SSTD或SPAY，56a域只能选择56A和56C.
        if ("SSTD".equals(field23B.getValue()) || "SPAY".equals(field23B.getValue())) {
            if(!isFieldEmpty(invoke("getField56D"))) {
                mtResult.addDescription(Language.getLanguage("MT103_C10_2", "MT103"));
            }
            //选择56C时，必须使用Clearing Code.
            //TODO 56C暂时不考虑，此处测试暂时搁置。
            if(!isFieldEmpty(invoke("getField56C"))) {
                List<String> clearingCodes = Arrays.asList("//AT", "//AU", "//BL", "//CC", "//CH", "//CN", "//CP", "//ES"
                        , "//FW", "//GR", "//HK", "//IE", "//IN", "//IT", "//NZ", "//PL", "//PT", "//RT", "//RU", "//SC", "//SW");
                boolean containsCode = false;
                for (String code : clearingCodes) {
                    Field56C field56C=invoke("getField56C");
                    if(field56C.getComponent1().contains(code)) {
                        containsCode = true;
                        break;
                    }
                }
                if(!containsCode){
                    mtResult.addDescription(Language.getLanguage("MT103_C10_3", "MT103"));
                }
            }
        }
        //校验规则11.
        //23B的值为SPRI, SSTD, SPAY时，57a只能选择57A, 57C, 57D. 57D必须使用Party Identifier.
        // Field57D field57D = mt103.getField57D();
        Field57D field57D = invoke("getField57D");
        switch (field23B.getValue()) {
            case "SPRI":
            case "SSTD":
            case "SPAY":
                if(!isFieldEmpty(invoke("getField57B"))) {
                    mtResult.addDescription(Language.getLanguage("MT103_C11_1", "MT103"));
                }
                // Field57D的Component列表中各元素的值与Info, Party Identifier, Address的对应关系会随着这三项的填写情况而发生改变。
                // 当填写Info, Party Identifier, Address时，Component2为Info, Component3为Party Identifier, Component4为Address.
                // 当不填写Info时，Component2为Party Identifier, Component3为Address.
                // 当不填写Party Identifier时，Component2为Info, Component3为Address.
                // 当只填写Address时，Component3为Address, Component2为空。
                // 不论哪种情况，Component1都为空，Components列表的长度都为6

                // 由于Info属于Party Identifier的一部分，可以通过Component2是否为空来判断是否填写了Party Identifier.
                // 当既没有填写Info也没有填写Party Identifier时，Component2为空。
                // 只要填写了其中一个，Component2就不为空。
                if(!isFieldEmpty(field57D)) {
                    //Component2.
                    String field57DComponent2 = field57D.getComponent2();
                    //Component2为空，说明没有填写Party Identifier.
                    if (StringUtils.isEmpty(field57DComponent2)) {
                        mtResult.addDescription(Language.getLanguage("MT103_C11_2", "MT103"));
                    }
                }
                break;
            default:
                break;
        }
        //校验规则12.
        //23B的值为SPRI, SSTD, SPAY时，59a必须填写Account.
//        Field59 field59 = mt103.getField59();
//        Field59A field59A = mt103.getField59A();
//        Field59F field59F = mt103.getField59F();

        Field59 field59 = invoke("getField59");
        Field59A field59A = invoke("getField59A");
        Field59F field59F = invoke("getField59F");
        String field59Acct = null;
        String field59AAcct = null;
        String field59FAcct = null;
        if(!isFieldEmpty(field59)) {field59Acct = field59.getAccount();}
        if(!isFieldEmpty(field59A)) {field59AAcct = field59A.getAccount();}
        if(!isFieldEmpty(field59F)) {field59FAcct = field59F.getAccount();}
        switch (field23B.getValue()) {
            case "SPRI":
            case "SSTD":
            case "SPAY":
                if(!isFieldEmpty(field59)  && StringUtils.isEmpty(field59Acct)) {
                    mtResult.addDescription(Language.getLanguage("MT103_C12_1", "MT103"));
                }
                if(!isFieldEmpty(field59A) && StringUtils.isEmpty(field59AAcct)) {
                    mtResult.addDescription(Language.getLanguage("MT103_C12_2", "MT103"));
                }
                if(!isFieldEmpty(field59F) && StringUtils.isEmpty(field59FAcct)) {
                    mtResult.addDescription(Language.getLanguage("MT103_C12_3", "MT103"));
                }
                break;
            default:
                break;
        }
        //校验规则13.
        //当有23E的值为CHQB时，59a不能填写Account.
        if(_23eValues != null) {
            for (String value : _23eValues) {
                if ("CHQB".equals(value)) {
                    if(StringUtils.isNotEmpty(field59Acct)) {
                        mtResult.addDescription(Language.getLanguage("MT103_C13_1", "MT103"));
                        break;
                    }
                    if(StringUtils.isNotEmpty(field59AAcct)) {
                        mtResult.addDescription(Language.getLanguage("MT103_C13_2", "MT103"));
                        break;
                    }
                    if(StringUtils.isNotEmpty(field59FAcct)) {
                        mtResult.addDescription(Language.getLanguage("MT103_C13_3", "MT103"));
                        break;
                    }
                }
            }
        }
        //校验规则14.
        //当71A的值为OUR时，71F不能存在。
        //当71A的值为SHA时，71G不能存在。
        //当71A的值为BEN时，71F必须存在，71G不能存在。
        Field71A field71A=invoke("getField71A");
        switch (field71A.getValue()) {
            case "OUR":
                List<Field71F> field71F=invoke("getField71F");
                if(field71F!= null && !field71F.isEmpty()) {
                    mtResult.addDescription(Language.getLanguage("MT103_C14_1", "MT103"));
                }
                break;
            case "SHA":
                Field71G field71G=invoke("getField71G");
                if(!isFieldEmpty(field71G)) {
                    mtResult.addDescription(Language.getLanguage("MT103_C14_2", "MT103"));
                }
                break;
            case "BEN":

                List<Field71F> field71FbenList=invoke("getField71F");
                Field71G field71Gben=invoke("getField71G");


                if((field71FbenList == null || field71FbenList.isEmpty()) ||
                        !isFieldEmpty(field71Gben)) {
                    mtResult.addDescription(Language.getLanguage("MT103_C14_3", "MT103"));
                }
                break;
            default:
                break;
        }
        //校验规则15.
        //当71F或71G存在时，33B必须存在。
        List<Field> field71F = invoke("getField71F");
        Field71G field71G=invoke("getField71G");
        Field33B field33B1=invoke("getField33B");
        if((field71F != null && !field71F.isEmpty()) ||
                !isFieldEmpty(field71G)) {
            if(isFieldEmpty(field33B1)) {
                mtResult.addDescription(Language.getLanguage("MT103_C15", "MT103"));
            }
        }
        //校验规则16.
        //当56a不存在时，23E不能包含TELI和PHOI.
        if(isFieldListAllEmpty(new ArrayList<Field>() {{
//            add(mt103.getField56A());
//            add(mt103.getField56C());
//            add(mt103.getField56D());
            add(invoke("getField56A"));
            add(invoke("getField56C"));
            add(invoke("getField56D"));
        }})) {
            if(_23eValues != null) {
                for (String value : _23eValues) {
                    if ("TELI".equals(value) || "PHOI".equals(value)) {
                        mtResult.addDescription(Language.getLanguage("MT103_C16", "MT103"));
                    }
                }
            }
        }
        //校验规则17.
        //当57a不存在时，23E不能包含TELE和PHON.
        if(isFieldListAllEmpty(new ArrayList<Field>() {{
//            add(mt103.getField57A());
//            add(mt103.getField57B());
//            add(mt103.getField57C());
//            add(mt103.getField57D());
            add(invoke("getField57A"));
            add(invoke("getField57B"));
            add(invoke("getField57C"));
            add(invoke("getField57D"));
        }})) {
            if(_23eValues != null) {
                for (String value : _23eValues) {
                    if ("TELE".equals(value) || "PHON".equals(value)) {
                        mtResult.addDescription(Language.getLanguage("MT103_C17", "MT103"));
                    }
                }
            }
        }
        //校验规则18.
        //71G和32A的币种必须相同。
        //判断71G是否为空。32A必填，此处跳过判断。

        Field71G field71G1=invoke("getField71G");
        Field32A field32A1=invoke("getField32A");
        if(!isFieldEmpty(field71G1) &&
                !Objects.equals(field71G1.getCurrency(),field32A1.getCurrency())) {
            mtResult.addDescription(Language.getLanguage("MT103_C18", "MT103"));
        }
        //return  mtResult;
    }


    public <T> T invoke(String method)
    {
        try {
            return (T) MethodUtils.invokeMethod(abstractMT,method);
        } catch (Exception e) {
            e.printStackTrace();
            mtResult.setSuccess(false);
            //mtResult.addDescription("业务层级validator错误:"+e.getMessage());
            mtResult.addDescription(Language.getLanguage("SYS_C29")+e.getMessage());
        }
        return null;

    }

    public AbsMTValidator(String mtStr, MtResult mtResult) {
        try {
            this.mtStr = mtStr;
            this.mtResult = mtResult;
            this.abstractMT = AbstractMT.parse(this.mtStr);
            String tempMsgType = this.abstractMT.getMessageType();
            SwiftBlock3 block3 = this.abstractMT.getSwiftMessage().getBlock3();
            if(block3!=null){
                Map<String, String> tagMap = block3.getTagMap();
                //判断为COV报文
                if (tagMap.containsKey("119") && "COV".equals(tagMap.get("119"))) {
                    tempMsgType = tempMsgType + "COV";
                }
            }
            this.msgType = tempMsgType;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public AbsMTValidator() {

    }

    public AbstractMT getAbstractMT() {
        return abstractMT;
    }

    public void setAbstractMT(AbstractMT abstractMT) {
        this.abstractMT = abstractMT;
    }

    public String getMtStr() {
        return mtStr;
    }

    public void setMtStr(String mtStr) {
        this.mtStr = mtStr;
    }

    public String getMsgType() {
        return msgType;
    }

    public void setMsgType(String msgType) {
        this.msgType = msgType;
    }

    public MtResult getMtResult() {
        return mtResult;
    }

    public void setMtResult(MtResult mtResult) {
        this.mtResult = mtResult;
    }


    public abstract void bussinessValidator();

}
