package com.dgtly.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dgtly.common.utils.StringUtils;
import com.dgtly.common.utils.http.HttpUtils;
import com.dgtly.system.domain.ApplicationContextProvider;
import com.dgtly.system.mapper.HanaSalesOrderMapper;
import com.dgtly.system.service.HanaSalesOrderService;
import com.dgtly.system.util.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.jdbc.datasource.init.DatabasePopulatorUtils.execute;

@Service
public class HanaSalesOrderServiceImpl implements HanaSalesOrderService {

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

    /** 批量删除每批最大条数，避免 IN 语句过长 */
    private static final int BATCH_SIZE = 500;

    private String sapResult;

    /** 通知 SAP 取消要货的 ESB 接口名称（固定值） */
    private static final String ESB_SERVICE_NAME = "ZSD_SSB_DELIV_INFO_IF";

    /** 取消要货时传给 SAP 的 TRANSPORT 字段值 */
    private static final String CANCEL_TRANSPORT = "交货冻结";

    @Autowired
    private HanaSalesOrderMapper hanaSalesOrderMapper;

    /** Spring Retry 重试模板 */
    @Autowired
    private RetryTemplate retryTemplate;

    /** ESB 通用接口地址（从配置文件读取） */
    @Value("${spring.esb.esbOrderCancelUrl}")
    private String esbOrderCancelUrl;

    /**
     * @description: 未过信的经销商订单的要货记录id（做逻辑删除，重新要货）
     * @param: []
     * @return: void
     * @author: njs
     * @date: 2023/6/16 14:35
     */
    @Override
    public void updateSalesOrderBaseNoCrditStatus() {
        List<String> orderBaseList = hanaSalesOrderMapper.selectOrderBaseList();
        if(orderBaseList !=null && orderBaseList.size()>0){
            hanaSalesOrderMapper.deleteLogic(orderBaseList);
        }
    }

    public String getSapResult() {
        return sapResult;
    }

    /**
     * @description: 交货冻结取货定时任务
     *               查询已冻结经销商（不在白名单中）且订单状态满足条件、尚未完全发货的要货记录，
     *               执行逻辑删除（is_delete = '1'）以取消要货，并记录操作日志。
     *               取消后逐条调用 ESB 接口 ZSD_SSB_DELIV_INFO_IF 通知 SAP，TRANSPORT 字段传"交货冻结"。
     * @return: 已取消的要货记录详情列表（含 customerCode/orderNumber/confirmBy），供调用方做企微通知
     */
    @Override
    public List<Map<String, Object>> cancelFreezeCustomerOrder() {
        log.info("【交货冻结取货】定时任务开始执行");

        // 先查详情，用于日志记录和企微通知（含 customerCode/orderNumber/confirmBy）
        List<Map<String, Object>> detailList = hanaSalesOrderMapper.selectFreezeCustomerOrderDetailList();
        if (detailList == null || detailList.isEmpty()) {
            log.info("【交货冻结取货】未查询到需要取消的要货记录，任务结束");
            return Collections.emptyList();
        }

        // 提取 id 列表
        List<String> orderIdList = detailList.stream()
                .map(m -> String.valueOf(m.get("id")))
                .collect(Collectors.toList());

        log.info("【交货冻结取货】共查询到需要取消的要货记录 {} 条，开始分批执行逻辑删除", orderIdList.size());
        int total = orderIdList.size();
        int deleted = 0;
        for (int i = 0; i < total; i += BATCH_SIZE) {
            List<String> batch = orderIdList.subList(i, Math.min(i + BATCH_SIZE, total));
            int rows = hanaSalesOrderMapper.cancelFreezeCustomerOrderLogic(batch);
            deleted += rows;
            log.info("【交货冻结取货】已处理批次 {}/{}, 本批影响行数: {}",
                    (i / BATCH_SIZE + 1), (int) Math.ceil((double) total / BATCH_SIZE), rows);
        }
        log.info("【交货冻结取货】逻辑删除完成，共取消要货记录 {} 条", deleted);

        // ---- 操作日志：按经销商分组输出结构化日志 ----
        String cancelTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        Map<String, List<String>> customerOrderMap = new LinkedHashMap<>();
        Map<String, Set<String>> customerConfirmByMap = new LinkedHashMap<>();
        for (Map<String, Object> detail : detailList) {
            String customerCode = String.valueOf(detail.get("customerCode"));
            String orderNumber  = String.valueOf(detail.get("orderNumber"));
            String confirmBy    = detail.get("confirmBy") != null ? String.valueOf(detail.get("confirmBy")) : "";
            customerOrderMap.computeIfAbsent(customerCode, k -> new ArrayList<>()).add(orderNumber);
            customerConfirmByMap.computeIfAbsent(customerCode, k -> new LinkedHashSet<>()).add(confirmBy);
        }
        for (Map.Entry<String, List<String>> entry : customerOrderMap.entrySet()) {
            String customerCode = entry.getKey();
            List<String> orderNumbers = entry.getValue();
            Set<String> confirmBys = customerConfirmByMap.get(customerCode);
            log.info("【交货冻结取货-操作日志】 取消时间={}, 经销商编码={}, 要货人={}, 取消订单号={}",
                    cancelTime, customerCode,
                    String.join(",", confirmBys),
                    String.join(",", orderNumbers));
        }

        // ---- 逐条通知 SAP：调用 ESB 接口 ZSD_SSB_DELIV_INFO_IF ----
        log.info("【交货冻结取货】开始通知 SAP，共 {} 条，ESB接口={}", detailList.size(), ESB_SERVICE_NAME);
        int esbSuccess = 0;
        int esbFail    = 0;
        Set<String> orderNumberSet = new HashSet<>();
        for (Map<String, Object> detail : detailList) {
            String orderNumber = String.valueOf(detail.get("orderNumber"));
            try {
                //调用sap不重复发
                if (orderNumberSet.add(orderNumber)){
                    notifySapCancelOrder(orderNumber);
                    esbSuccess++;
                }
            } catch (Exception e) {
                esbFail++;
                log.error("【交货冻结取货】ESB 通知 SAP 失败，订单号={}", orderNumber, e);
            }
        }
        log.info("【交货冻结取货】ESB 通知 SAP 完成，成功={} 条，失败={} 条", esbSuccess, esbFail);

        return detailList;
    }



    /**
     * 调用 ESB 接口 ZSD_SSB_DELIV_INFO_IF 通知 SAP 取消指定要货订单。
     * TRANSPORT 字段固定传"交货冻结"。
     *
     * @param orderNumber 要取消的订单号（sales_order_base.order_number）
     */
    private  void notifySapCancelOrder(String orderNumber) {
        String uuidStr = UUID.randomUUID().toString();

        // 请求头
        Map<String, String> headers = new HashMap<>(8);
        headers.put("Content-Type", "application/json");
        headers.put("requestId",    uuidStr);
        headers.put("trackId",      uuidStr);
        headers.put("sourceSystem", "SSB");
        headers.put("serviceName",  "S_SSB_ERP_ZsdSsbDelivInfoIf_S");

        List<Map<String, String>> params =new ArrayList<>();
        Map<String, String> maps = new HashMap<>(7);
        maps.put("VBELN", orderNumber);
        maps.put("POSNR", "000000");
        maps.put("KWMENG_2", "0");
        maps.put("KWMENG_1", "0");
        maps.put("ZYZH", "system");
        maps.put("DATE", format(new Date(), "yyyyMMdd"));
        maps.put("TIME", format(new Date(), "HHmmss"));
        maps.put("TRANSPORT",  CANCEL_TRANSPORT);
        params.add( maps);
        Map<String, List<Map<String, String>>> item = new HashMap<>(1);
        item.put("item", params);
        Map<String, Map<String, List<Map<String, String>>>> itData = new HashMap<>(1);
        itData.put("IT_DATA", item);
        Map<String, Map<String, Map<String, List<Map<String, String>>>>> zsdSsbDelivInfoIf = new HashMap<>(1);
        zsdSsbDelivInfoIf.put("ZSD_SSB_DELIV_INFO_IF", itData);

        log.info("【交货冻结取货】ESB 通知 SAP，订单号={}，请求报文={}", orderNumber, params);
        boolean execute = false;
        try {
            execute = retry("http://esb-test.nipponpaint.com.cn/esb/erp/api", headers, zsdSsbDelivInfoIf);
        } catch (Exception e) {
            log.error("[{}] retry error,  headers is [{}], params is [{}]", "http://esb-test.nipponpaint.com.cn/esb/erp/api", JSON.toJSONString(headers), JSON.toJSONString(zsdSsbDelivInfoIf), e);
        }
        log.info("【交货冻结取货】ESB 响应，订单号={}，响应={}", orderNumber, execute);

//        // 解析响应，非成功时抛出异常由调用方记录
//        JSONObject jsonResult = JSONObject.parseObject(result);
//        if (jsonResult != null && jsonResult.containsKey("code")) {
//            Object code = jsonResult.get("code");
//            if (!"0".equals(String.valueOf(code)) && !"200".equals(String.valueOf(code))) {
//                throw new RuntimeException("ESB 返回非成功状态，code=" + code
//                        + "，msg=" + jsonResult.getString("msg"));
//            }
//        }
    }
    public static String format(Date date, String format) {
        if (null != date && !StringUtils.isEmpty(format)) {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.format(date);
        } else {
            return null;
        }
    }
    public boolean retry(String url, Map<String, String> headers, Map<String, Map<String, Map<String, List<Map<String, String>>>>> params) throws Exception {
        return retryTemplate.execute(
                context -> execute(url, headers, params),
                context -> {
                    log.error("[{}] final request retry fail , headers is [{}], params is [{}]", url, JSON.toJSONString(headers), JSON.toJSONString(params), context.getLastThrowable());
                    return false;
                });
    }
    private boolean execute(String url, Map<String, String> headers, Map<String, Map<String, Map<String, List<Map<String, String>>>>> params) throws Exception {
        String returnString = HttpUtil.executePostBodyJsonParamRetry(url, headers, params);
        log.info("SendOrderExpectedTimeToSapTask headers = [{}],  params = [{}], returnString = [{}]", headers, params, returnString);
        this.sapResult = returnString;
        JSONObject jsonObject = JSON.parseObject(returnString);
        JSONObject zsdSsbDelivInfoIfResponse = jsonObject.getJSONObject("ZSD_SSB_DELIV_INFO_IFResponse");
        String code = zsdSsbDelivInfoIfResponse.getString("EV_FLAG");
        return org.apache.commons.lang3.StringUtils.equals("S", code);
    }

//    public static void main(String[] args) {
//        notifySapCancelOrder("1231111111");
//    }


}


