package com.fs.his.controller;

import com.baidu.dev2.thirdparty.commons.codec.digest.DigestUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fs.erp.dto.tl.dto.*;
import com.fs.erp.service.TlErpOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.util.*;

/**
 * 聚水潭[兔灵]消息推送-回调接口
 */
@Slf4j
@RestController
@RequestMapping("/sync/order/jst")
public class JstOrderSyncController {

    @Autowired
    private TlErpOrderService jstErpHttpService;

    @Autowired
    private ObjectMapper objectMapper;

    //聚水潭官方文档说对于回调请求 partnerKey 和 partnerid 的值相同
    private static final String PARTNER_ID = "erp";
    private static final String PARTNER_KEY = "erp";

    private static final Set<String> SUPPORTED_METHODS;

    static {
        Set<String> supported = new HashSet<>();
        supported.add("logistics.upload");
        supported.add("cancel.order");
        supported.add("inventory.upload");
        supported.add("refund.goods");
        SUPPORTED_METHODS = Collections.unmodifiableSet(supported);
    }

    /**
     * 聚水潭erp物流回调接口
     * URL: POST /open/callback?partnerid=erp&method=logistics.upload&ts=xxx&sign=xxx
     * 其中取消订单回调传入了token，其他接口没有，暂时还不知道这个token的作用
     */
    @PostMapping("/open/callback")
    public ResponseEntity<PushResponse> handleCallback(
            @RequestParam String partnerid,
            @RequestParam String method,
            @RequestParam Long ts,
            @RequestParam String sign,
            @RequestParam(required = false) String token, // token 未在当前逻辑中使用
            @RequestBody String rawBody) {

        log.info("收到聚水潭[兔灵]回调, method={}, ts={}, rawBody={}", method, ts, rawBody);

        // 1. 调用封装的校验方法
        ResponseEntity<PushResponse> validationResponse = validateRequest(partnerid, method, ts, sign);
        if (validationResponse != null) {
            // 如果校验失败，直接返回错误响应
            return validationResponse;
        }

        // 2. 根据 method 反序列化并处理
        try {
            if ("inventory.upload".equals(method)) {
                //处理聚水潭库存同步回调
                JstInventoryPushDTO req = objectMapper.readValue(rawBody, JstInventoryPushDTO.class);
                jstErpHttpService.jSTanErpInventoryCallback(req);
            } else if ("cancel.order".equals(method)) {
                //处理聚水潭取消订单回调
                JstCancelOrderDTO req = objectMapper.readValue(rawBody, JstCancelOrderDTO.class);
                jstErpHttpService.jSTanErpCancelOrderCallback(req);
            } else if ("logistics.upload".equals(method)) {
                //处理聚水潭物流同步回调
                JstLogisticsPushDTO req = objectMapper.readValue(rawBody, JstLogisticsPushDTO.class);
                jstErpHttpService.jSTanErpLogisticsCallback(req);
            } else if ("refund.goods".equals(method)) {
                //处理聚水潭售后收货回调
                JstRefundGoodsDTO req = objectMapper.readValue(rawBody, JstRefundGoodsDTO.class);
                jstErpHttpService.jSTanErpRefundGoodsCallback(req);
            } else {
                // 理论上这步不会走到，因为 validateRequest 已经检查过了
                return ResponseEntity.ok(new PushResponse("1", "unknown method"));
            }
            return ResponseEntity.ok(new PushResponse("0", "执行成功"));
        } catch (Exception e) {
            log.error("处理聚水潭回调异常, method={}", method, e);
            return ResponseEntity.ok(new PushResponse("1", "system error"));
        }
    }

    /**
     * 封装的请求校验方法
     *
     * @param partnerid 请求中的 partnerid
     * @param method    请求中的 method
     * @param ts        请求中的时间戳
     * @param sign      请求中的签名
     * @return 如果校验失败，返回包含错误信息的 ResponseEntity；如果校验成功，返回 null。
     */
    private ResponseEntity<PushResponse> validateRequest(String partnerid, String method, Long ts, String sign) {
        // 1. 校验 partnerid
        if (!PARTNER_ID.equals(partnerid)) {
            log.warn("校验失败: invalid partnerid={}", partnerid);
            return ResponseEntity.ok(new PushResponse("1", "invalid partnerid"));
        }

        // 2. 校验 method
        if (!SUPPORTED_METHODS.contains(method)) {
            log.warn("校验失败: 不支持的 method={}", method);
            return ResponseEntity.ok(new PushResponse("1", "unsupported method"));
        }

        // 3. 校验时间戳
        long now = Instant.now().getEpochSecond();
        if (Math.abs(now - ts) > 600) { // 允许 10 分钟的时间差
            log.warn("校验失败: ts expired, now={}, ts={}", now, ts);
            return ResponseEntity.ok(new PushResponse("1", "ts expired"));
        }

        // 4. 验签（注意：sign 拼接规则不含 token！）
        String signSource = method + partnerid + "ts" + ts + PARTNER_KEY;
        String expectedSign = DigestUtils.md5Hex(signSource).toLowerCase();
        if (!expectedSign.equals(sign)) {
            log.warn("校验失败: 签名校验失败, method={}, ts={}, expectedSign={}, receivedSign={}", method, ts, expectedSign, sign);
            return ResponseEntity.ok(new PushResponse("1", "invalid sign"));
        }

        // 所有校验通过
        return null;
    }
}