package nccloud.api.so.saleinvoice.operator;

import nc.bs.framework.common.NCLocator;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pubapp.pattern.log.Log;
import nc.vo.pubapp.pattern.pub.MathTool;
import nc.vo.pubapp.scale.ScaleUtils;
import nc.vo.scmpub.util.ValueCheckUtil;
import nc.vo.so.m32.entity.SaleInvoiceBVO;
import nc.vo.so.m32.entity.SaleInvoiceVO;
import nc.vo.so.m32trantype.entity.M32TranTypeVO;
import nc.vo.so.m32trantype.enumeration.Finvoicetime;
import nc.vo.so.pub.enumeration.BillStatus;
import nc.vo.so.pub.util.AggVOUtil;
import nccloud.framework.core.exception.ExceptionUtils;
import nccloud.itf.sscivm.ivsale.service.ExchangeToIvAppService;
import nccloud.pubitf.so.saleinvoice.service.IM32TransTypeService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class ApplicationRedInvoiceService {
    private static final String REDINVOICEMNYDEALFORSSC = "redinvoicemnydealforssc";// 红字发票传开票申请数据处理
    private static final String SL = "sl"; // 税率
    private static final String SESUM = "sesum"; // 税额合计
    private static final String JSHJSUM = "jshjsum"; // 价税合计
    private static final String JESUM = "jesum"; // 无税金额合计

    /**
     * 销售发票判断是否可以开红字发票
     *
     * @param vos
     * @return
     */
    public List<Map<String, String>> getData(SaleInvoiceVO[] vos) {
        Map<String, List<Map<String, String>>> dealMnyMap = new HashMap<String, List<Map<String, String>>>();
        try {
            Map<String, Boolean> isCanGenerateMap = this.checkInvoiceStatus(AggVOUtil.getPrimaryKeys(vos));
            Map<String, M32TranTypeVO> invoicetime = this.qryinvoicetime(vos);

            for (SaleInvoiceVO vo : vos) {
                Boolean isCan = isCanGenerateMap.get(vo.getParentVO().getPrimaryKey());
                if (isCan == null || !isCan) {
                    ExceptionUtils.wrapBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("4006013_0",
                            "04006013-0039", null, new String[]{vo.getParentVO().getVbillcode()})/* 发票{0}已经开票，不能再进行开票！ */);
                }

                Integer fstatusflag = vo.getParentVO().getFstatusflag();
                if (null != invoicetime && Finvoicetime.FINVOICETIEMAPPROVEAFTER
                        .equalsValue(invoicetime.get(vo.getParentVO().getCtrantypeid()).getFinvoicetime())) {
                    if (!BillStatus.AUDIT.getIntegerValue().equals(fstatusflag)) {
                        ExceptionUtils.wrapBusinessException(nc.vo.ml.NCLangRes4VoTransl
                                .getNCLangRes().getStrByID("4006013_0", "04006013-0141", null, new String[]{vo.getParentVO().getVbillcode()})/* @res "发票{0}的状态不是审批通过状态，不能进行红字发票处理！" */);
                    }
                } else if (null != invoicetime && Finvoicetime.FINVOICETIEMAPPROVEBEFORE
                        .equalsValue(invoicetime.get(vo.getParentVO().getCtrantypeid()).getFinvoicetime())) {
                    if (BillStatus.AUDIT.getIntegerValue().equals(fstatusflag)) {
                        if (isCan == null || isCan) {
                            ExceptionUtils
                                    .wrapBusinessException(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
                                            .getStrByID("4006013_0", "04006013-0146", null, new String[]{vo.getParentVO().getVbillcode()})/* @res "发票{0}的交易类型属性税务发票开票时机为先开票后审批通过，已审批通过不允许开票！" */);
                        }
                    }
                }
            }
            // 根据税率分组，Map<税率,Map<价税合计,税额>>
            dealMnyMap = this.dealMnyForSSC(vos);
        } catch (Exception e) {
            ExceptionUtils.wrapException(e);
        }
        return dealMnyMap.get(REDINVOICEMNYDEALFORSSC);
    }

    /**
     * 检查是否存在已生成、发票未作废的开票申请;能否继续操作
     *
     * @param billIds
     * @return (true / 未不包含有效下游单据 ， 可继续开票 ， 或业务单据逆向操作 ； false / 为包含下游单据 ， 业务领域控制不允许继续开票 ， 或业务单据逆向操作 ；)
     * @throws BusinessException
     */
    private Map<String, Boolean> checkInvoiceStatus(String[] billIds) throws BusinessException {
        if (ValueCheckUtil.isNullORZeroLength(billIds)) {
            return new HashMap<String, Boolean>();
        }
        /*if (!SysInitGroupQueryNcc.isEndable("1058")) {
            return new HashMap<String, Boolean>();
        }*/
        ExchangeToIvAppService exchangeToIvAppService = NCLocator.getInstance().lookup(ExchangeToIvAppService.class);
        return exchangeToIvAppService.checkApplicationStatus(billIds);
    }

    /**
     * 查询交易类型开票时机
     *
     * @param vos
     * @throws BusinessException
     */
    private Map<String, M32TranTypeVO> qryinvoicetime(SaleInvoiceVO[] vos) throws BusinessException {
        Map<String, M32TranTypeVO> tranttypeMap = new HashMap<String, M32TranTypeVO>();
        List<String> trantypeids = new ArrayList<String>();
        // 查询发票交易类型的税务发票开票时机
        for (SaleInvoiceVO vo : vos) {
            trantypeids.add(vo.getParentVO().getCtrantypeid());
        }
        // 默认先审批通过后开票
        if (null != trantypeids && !trantypeids.isEmpty()) {
            try {
                IM32TransTypeService service = NCLocator.getInstance().lookup(IM32TransTypeService.class);
                tranttypeMap = service.queryM32TranType(trantypeids.toArray(new String[0]));
            } catch (Exception e) {
                Log.info(e);
                ExceptionUtils.wrapException(e);
            }
        }
        if (null != tranttypeMap && !tranttypeMap.isEmpty()) {
            return tranttypeMap;
        }
        return null;
    }

    /**
     * 处理表体发票数据，根据税率分组
     *
     * @param vos
     * @return Map<String, List < Map < String, UFDouble>>>:Map<REDINVOICEMNYDEALFORSSC,List<Map<税率/税额/价税合计,UFDouble>>>
     * @throws BusinessException
     */
    private Map<String, List<Map<String, String>>> dealMnyForSSC(SaleInvoiceVO[] vos) {
        Map<String, List<Map<String, String>>> mnyDealForSSCMap = new HashMap<String, List<Map<String, String>>>();
        Map<UFDouble, String> ntaxrateGroupMap = new HashMap<UFDouble, String>();
        for (SaleInvoiceVO vo : vos) {
            SaleInvoiceBVO[] bvos = vo.getChildrenVO();
            for (SaleInvoiceBVO bvo : bvos) {
                // 税率
                UFDouble ntaxrate = bvo.getNtaxrate();
                // 税额
                UFDouble ntax = bvo.getNtax();
                // 价税合计
                UFDouble norigtaxmny = bvo.getNorigtaxmny();
                // 无税金额
                UFDouble norigmny = bvo.getNorigmny();
                if (ntaxrateGroupMap.containsKey(bvo.getNtaxrate())) {
                    String dealmny = ntaxrateGroupMap.get(ntaxrate);
                    String[] splitmny = dealmny.split(",");
                    UFDouble oldntax = new UFDouble(Double.valueOf(splitmny[0]));
                    UFDouble oldnorigtaxmny = new UFDouble(Double.valueOf(splitmny[1]));
                    UFDouble oldnorigmny = new UFDouble(Double.valueOf(splitmny[2]));
                    UFDouble ntaxsum = MathTool.add(ntax, oldntax);
                    UFDouble norigtaxmnysum = MathTool.add(norigtaxmny, oldnorigtaxmny);
                    UFDouble norigmnysum = MathTool.add(norigmny, oldnorigmny);
                    ntaxrateGroupMap.put(ntaxrate, ntaxsum + "," + norigtaxmnysum + "," + norigmnysum);
                } else {
                    ntaxrateGroupMap.put(ntaxrate, ntax + "," + norigtaxmny + "," + norigmny);
                }
            }

            List<Map<String, String>> mnyDealForSSCList = new ArrayList<Map<String, String>>();
            for (Entry<UFDouble, String> dealmny : ntaxrateGroupMap.entrySet()) {
                Map<String, String> mnyDealforSSCMap = new HashMap<String, String>();
                UFDouble dealtaxrate = dealmny.getKey();
                String[] splitdealmny = dealmny.getValue().split(",");
                UFDouble dealnatx = new UFDouble(Double.valueOf(splitdealmny[0]));
                dealnatx = ScaleUtils.adjustScale(dealnatx, 2);
                UFDouble dealnorigtaxmny = new UFDouble(Double.valueOf(splitdealmny[1]));
                dealnorigtaxmny = ScaleUtils.adjustScale(dealnorigtaxmny, 2);
                UFDouble dealnorigmny = new UFDouble(Double.valueOf(splitdealmny[2]));
                dealnorigmny = ScaleUtils.adjustScale(dealnorigmny, 2);
                // 税率
                mnyDealforSSCMap.put(SL, dealtaxrate.toString());
                // 税额合计
                mnyDealforSSCMap.put(SESUM, dealnatx.toString());
                // 价税合计
                mnyDealforSSCMap.put(JSHJSUM, dealnorigtaxmny.toString());
                // 无税金额合计
                mnyDealforSSCMap.put(JESUM, dealnorigmny.toString());
                mnyDealForSSCList.add(mnyDealforSSCMap);
            }
            mnyDealForSSCMap.put(REDINVOICEMNYDEALFORSSC, mnyDealForSSCList);
        }
        return mnyDealForSSCMap;
    }
}
