package nc.bs.ic.m4c.sign.rule;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import nc.bs.dao.BaseDAO;
import nc.bs.framework.common.NCLocator;
import nc.bs.logging.Log;
import nc.impl.pubapp.pattern.rule.IRule;
import nc.jdbc.framework.processor.ColumnProcessor;
import nc.vo.bd.cust.CustomerVO;
import nc.vo.bd.material.MaterialVO;
import nc.vo.bd.material.measdoc.MeasdocVO;
import nc.vo.bd.psn.PsndocVO;
import nc.vo.bd.rack.RackVO;
import nc.vo.bd.stordoc.StordocVO;
import nc.vo.bd.supplier.SupplierVO;
import nc.vo.ic.m4c.entity.SaleOutBodyVO;
import nc.vo.ic.m4c.entity.SaleOutHeadVO;
import nc.vo.ic.m4c.entity.SaleOutVO;
import nc.vo.org.StockOrgVO;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFDate;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.pubapp.pattern.pub.SqlBuilder;
import nc.vo.vorg.DeptVersionVO;
import nccloud.pubift.commen.itf.utils.IHttpPostOtherSys;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;


/**
 * 销售出库（签字后传MES金思维系统）
 */
public class AfterSigningSynchronizeRuleMES implements IRule<SaleOutVO> {
    private static final String SALE_OUT_URL = "/GTHINKING/AjaxService/N_KCSJJS/101527003.ashx/gt_rec_api_xsckdj"; // 销售出库登记接口
    private static final Log obmlog = Log.getInstance("OALOG");
    private static final BaseDAO dao = new BaseDAO();
    IHttpPostOtherSys httpPostOtherSys = NCLocator.getInstance().lookup(IHttpPostOtherSys.class);

    public AfterSigningSynchronizeRuleMES() {
    }

    @Override
    public void process(SaleOutVO[] saleOutVOS) {
        try {
            if (saleOutVOS == null || saleOutVOS.length == 0) {
                obmlog.debug("AfterSigningSynchronizeRule-没有需要处理的销售出库单.");
                return;
            }
            // 检查并筛选组织为电缆的销售出库单
            List<SaleOutVO> filteredSaleOutVOS = checkAndFilterBills(saleOutVOS);
            if (filteredSaleOutVOS.isEmpty()) {
                obmlog.debug("AfterSigningSynchronizeRule-没有需要处理的组织为电缆的需要同步的销售出库单");
                return;
            }
            // 处理每个销售出库单
            for (SaleOutVO saleOutVO : filteredSaleOutVOS) {
                SaleOutHeadVO hvo = (SaleOutHeadVO) saleOutVO.getParentVO();
                SaleOutBodyVO[] bvos = (SaleOutBodyVO[]) saleOutVO.getChildrenVO();
                // 构建要发送的数据
                JSONObject syncData = buildSyncData(hvo, bvos);
                httpPostOtherSys.sendToExternalSystem(SALE_OUT_URL, syncData);
            }
        } catch (Exception e) {
            obmlog.error("AfterSigningSynchronizeRule-处理异常:" + e.getMessage(), e);
            ExceptionUtils.wrappException(e);
        }
    }

    /**
     * 构建符合金思维系统接口规范的请求数据
     * 按照NCC/YonBIP字段映射到金思维系统字段
     */
    private JSONObject buildSyncData(SaleOutHeadVO hvo, SaleOutBodyVO[] bvos) throws BusinessException {
        obmlog.debug("AfterSigningSynchronizeRule-开始处理销售出库单: " + hvo.getVbillcode());
        JSONObject requestData = new JSONObject();

        JSONObject dataObj = new JSONObject();
        // 主表数据 - 需要手输入
        dataObj.put("orderNo", hvo.getVbillcode());                   // 收货单号 - 单据号(vbillcode)
        // 日期格式转换
        UFDate dbilldate = hvo.getDbilldate();
        dataObj.put("orderDate", dbilldate.toString().substring(0, 10));  // 收货日期 - 单据日期(dbilldate)，格式：yyyy-MM-dd
        dataObj.put("planDate", dbilldate.toString().substring(0, 10));  // 计划日期 - 单据日期(dbilldate)，格式：yyyy-MM-dd
        dataObj.put("actureDate", dbilldate.toString().substring(0, 10));  // 实际日期 - 单据日期(dbilldate)，格式：yyyy-MM-dd
        dataObj.put("orderType", null);                               // 收货类型 - 无对应字段
        dataObj.put("type", "XSCK");                                 // 事务类型 - 销售出库
        // 汇率 默认为1
        dataObj.put("exRate", 1);
        // 部门ID - 部门(cdptvid)
        dataObj.put("departmentId", transferCodeByPk(DeptVersionVO.getDefaultTableName(),
                DeptVersionVO.CODE, DeptVersionVO.PK_VID, hvo.getCdptvid()));        // 采购部门ID
        // 仓库编码 - 仓库(cwarehouseid)
        dataObj.put("storeId", transferCodeByPk(StordocVO.getDefaultTableName(),
                StordocVO.CODE, StordocVO.PK_STORDOC, hvo.getCwarehouseid()));   // 仓库编码
        // 采购员 - 业务员(cbizpersonid)
        dataObj.put("purchaser", transferCodeByPk(PsndocVO.getDefaultTableName(),
                PsndocVO.NAME, PsndocVO.PK_PSNDOC, hvo.getCbizid()));
        // 客户ID - 订单客户(ccustomerid)，这里因为是采购所以用供应商映射
        dataObj.put("supplyId", transferCodeByPk(CustomerVO.getDefaultTableName(),
                CustomerVO.CODE, CustomerVO.PK_CUSTOMER, hvo.getCcustomerid()));
        // 发出
        dataObj.put("sType", "N");
        //出具发票
        dataObj.put("billing", "Y");
        //开票依据
        dataObj.put("billingBasis", "S");
        //有效日期
        dataObj.put("effDate", null);
        //寄售仓库ID
        dataObj.put("consignStoreId", null);
        // 生成方式
        dataObj.put("genType", null);
        //寄售事务类型
        dataObj.put("consignType", null);
        //经办人工号
        dataObj.put("operatorNo", null);
        //经办人
        dataObj.put("operatorName", null);
        //保管员
        dataObj.put("storeKeeper", null);
        //客户ID
        dataObj.put("customId", transferCodeByPk(CustomerVO.getDefaultTableName(), CustomerVO.CODE, CustomerVO.PK_CUSTOMER, hvo.getCcustomerid()));
        //生成标志
        dataObj.put("mark", "Y");
        //备注
        dataObj.put("remark", hvo.getVnote());
        // 构建Details明细数组
        JSONArray details = new JSONArray();
        if (bvos != null) {
            for (SaleOutBodyVO bvo : bvos) {
                JSONObject detail = new JSONObject();
                detail.put("orderNo", hvo.getVbillcode());           // 提货单ID - 单据号(vbillcode) - 必填
                detail.put("sequenceNum", bvo.getCrowno());          // 提货单序号 - 行号(crowno) - 必填
                detail.put("type", "XSCK");                          // 事务类型 - 默认XSCK
                // 来源单据信息
                detail.put("saleOrderNo", bvo.getVsourcebillcode()); // SOID - 来源单据号(vsourcebillcode)
                detail.put("saleSequenceNum", bvo.getVsourcerowno()); // SO序号 - 来源单据行号(vsourcerowno)
                detail.put("allocationNum", null);                   // 分配号
                // 物料信息 - 必填
                detail.put("materialId", transferCodeByPk(MaterialVO.getDefaultTableName(),
                        MaterialVO.CODE, MaterialVO.PK_MATERIAL, bvo.getCmaterialoid()));  // 物料ID - 必填

                detail.put("unit", transferCodeByPk(MeasdocVO.getDefaultTableName(),
                        MeasdocVO.CODE, MeasdocVO.PK_MEASDOC, bvo.getCunitid()));  // 计量单位 - 必填
                detail.put("productNum", null);                      // 制令号
                // 库位 - 必填
                detail.put("storageId", transferCodeByPk(RackVO.getDefaultTableName(),
                        RackVO.CODE, RackVO.PK_RACK, bvo.getClocationid())); // 库位 - 必填
                detail.put("batchNum", bvo.getVbatchcode());         // 物料批号 - 必填
                detail.put("scaleFactor", transferSpecialField(bvo.getVchangerate()));     // 换算系数 - 必填
                // 数量信息 - 必填
                detail.put("issuedQty", bvo.getNshouldassistnum() == null ? bvo.getNshouldassistnum().getDouble() : null);  // 应发数量 - 必填
                detail.put("mIssuedQty", bvo.getNshouldnum() == null ? bvo.getNshouldnum().getDouble() : null);       // 主应发数量 - 必填
                detail.put("actQry", bvo.getNassistnum() == null ? bvo.getNassistnum().getDouble() : null);           // 实发数量 - 必填
                detail.put("mActQry", bvo.getNnum() == null ? bvo.getNnum().getDouble() : null);                // 主实发数量 - 必填
                detail.put("assistActQry", bvo.getNassistnum() == null ? bvo.getNassistnum().getDouble() : null);     // 辅助实发数量 - 必填
                // 客户和供应商信息
                detail.put("customId", transferCodeByPk(CustomerVO.getDefaultTableName(),
                        CustomerVO.CODE, CustomerVO.PK_CUSTOMER, bvo.getCasscustid())); // 客户ID

                detail.put("supplierId", transferCodeByPk(SupplierVO.getDefaultTableName(),
                        SupplierVO.CODE, SupplierVO.PK_SUPPLIER, bvo.getCvendorid())); // 供应商ID
                detail.put("manufactureDate", bvo.getDproducedate()); // 生产日期
                detail.put("color", null);                           // 颜色
                detail.put("properties", null);
                detail.put("remark", bvo.getVnotebody());            // 备注 - 行备注(vnotebody)
                details.add(detail);
            }
        }
        requestData.put("operation_type", "I");
        requestData.put("info", dataObj);
        dataObj.put("details", details);
        return requestData;
    }

    /**
     * 检查并筛选需要同步的单据
     */
    private List<SaleOutVO> checkAndFilterBills(SaleOutVO[] saleOutVOS) {
        List<SaleOutVO> result = new ArrayList<>();
        for (SaleOutVO vo : saleOutVOS) {
            try {
                String code = transferCodeByPk(StockOrgVO.getDefaultTableName(), StockOrgVO.CODE, StockOrgVO.PK_STOCKORG, vo.getParentVO().getPk_org());
                if (httpPostOtherSys.checkIfIncludeOrg(code)) {
                    result.add(vo);
                }
            } catch (BusinessException e) {
                ExceptionUtils.wrappBusinessException("查询组织时发生错误");
            }
        }
        return result;
    }


    private String transferCodeByPk(String tableName, String selectField, String pkField, String pk) throws BusinessException {
        if (nc.vo.cmp.util.StringUtils.isEmpty(pk)) {
            return null;
        }
        SqlBuilder sqlBuilder = new SqlBuilder();
        sqlBuilder.append(" select " + selectField);
        sqlBuilder.append(" from " + tableName);
        sqlBuilder.append(" where ");
        sqlBuilder.append(pkField, pk);
        Object o = dao.executeQuery(sqlBuilder.toString(), new ColumnProcessor());
        if (o == null) {
            throw new BusinessException("未查询到编码信息，sql【" + sqlBuilder + "】");
        }
        return o.toString();
    }

    private String transferSpecialField(String field) {
        if (field == null || field.trim().isEmpty()) {
            return null;
        }
        String[] split = field.split("/");
        if (split.length == 2) {
            String numStr = split[0].trim();
            String denStr = split[1].trim();

            if (denStr.equals("0")) {
                return "0.00"; // 分母不能为零
            }

            try {
                BigDecimal numerator = new BigDecimal(numStr);
                BigDecimal denominator = new BigDecimal(denStr);
                return numerator.divide(denominator, 2, RoundingMode.HALF_UP).toString();
            } catch (NumberFormatException e) {
                return field; // 非法数字，返回原字段
            }
        }
        return field;
    }
}
