package shop.alien.store.service;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.AlipaySignature;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import shop.alien.entity.store.StorePaymentConfig;

import javax.servlet.http.HttpServletRequest;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 1）商户支付状态定时同步（无异步回调时的兜底），由 {@code payment.sync.enabled} 控制是否执行；<br/>
 * 2）支付宝开放平台<strong>消息通知</strong>：二级商户进件审核通过 {@code ant.merchant.expand.indirect.zft.passed}，
 * POST 至应用网关（请在开放平台配置网关 URL，例如 .../store/alipay/message/zft-passed），
 * 验签通过后更新门店支付配置中的二级商户标识等。
 *
 * @author system
 */
@Slf4j
@RestController
@RequestMapping("/store/alipay/message")
@RequiredArgsConstructor
public class MerchantPaymentSyncScheduler {

    private static final String MSG_ZFT_PASSED = "ant.merchant.expand.indirect.zft.passed";

    /** 为 false 时不跑同步任务；消息通知接口始终可用 */
    @Value("${payment.sync.enabled:false}")
    private boolean paymentSyncEnabled;

    /** 生产环境应为 true；本地联调可临时关闭验签 */
    @Value("${payment.alipay.zft-passed.verify-signature:true}")
    private boolean verifyZftPassedSignature;

    private final StorePaymentConfigService storePaymentConfigService;

    /**
     * 支付宝异步消息：直付通二级商户进件审核通过。
     * <p>
     * Content-Type: application/x-www-form-urlencoded，公共参数含 notify_id、utc_timestamp、msg_method、
     * app_id、version、biz_content、sign、sign_type、charset 等；biz_content 内含 order_id、smid、
     * external_id、card_alias_no、memo。
     * </p>
     * 处理成功请返回纯文本 {@code success}，失败返回 {@code fail}（支付宝将按策略重试）。
     */
    @PostMapping(value = "/zft-passed", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = "text/plain;charset=UTF-8")
    public String onZftPassedMessage(HttpServletRequest request) {
        try {
            Map<String, String> params = toSingleValueMap(request);
            String msgMethod = params.get("msg_method");
            if (!MSG_ZFT_PASSED.equals(msgMethod)) {
                log.debug("忽略非 zft.passed 消息 msg_method={}", msgMethod);
                return "success";
            }
            String appId = params.get("app_id");
            StorePaymentConfig config = storePaymentConfigService.getByAppId(appId);
            if (config == null) {
                log.warn("zft.passed 未找到 app_id 对应支付配置 appId={}", appId);
                return "fail";
            }
            if (verifyZftPassedSignature && !verifyAlipaySignature(params, config)) {
                log.warn("zft.passed 验签失败 appId={}", appId);
                return "fail";
            }
            String bizRaw = params.get("biz_content");
            if (StringUtils.isBlank(bizRaw)) {
                return "fail";
            }
            JSONObject biz = JSONObject.parseObject(bizRaw);
            applyZftPassed(config, biz);
            return "success";
        } catch (Exception e) {
            log.error("zft.passed 消息处理异常", e);
            return "fail";
        }
    }

    private void applyZftPassed(StorePaymentConfig config, JSONObject biz) {
        String smid = biz.getString("smid");
        if (StringUtils.isNotBlank(smid)) {
            config.setStoreAliId(smid);
        }
        log.info("直付通二级商户进件审核通过 storeId={} orderId={} smid={} externalId={} cardAliasNo={} memo={}",
                config.getStoreId(),
                biz.getString("order_id"),
                smid,
                biz.getString("external_id"),
                biz.getString("card_alias_no"),
                biz.getString("memo"));
        storePaymentConfigService.updateById(config);
    }

    private boolean verifyAlipaySignature(Map<String, String> params, StorePaymentConfig config) {
        if (config.getAlipayPublicCert() == null || config.getAlipayPublicCert().length == 0) {
            log.warn("验签失败：未配置支付宝公钥证书");
            return false;
        }
        Path temp = null;
        try {
            temp = Files.createTempFile("alipay_pub_", ".crt");
            Files.write(temp, config.getAlipayPublicCert());
            String signType = StringUtils.defaultIfBlank(params.get("sign_type"), "RSA2");
            return AlipaySignature.rsaCertCheckV1(params, temp.toAbsolutePath().toString(), "UTF-8", signType);
        } catch (Exception e) {
            log.error("支付宝消息验签异常", e);
            return false;
        } finally {
            if (temp != null) {
                try {
                    Files.deleteIfExists(temp);
                } catch (Exception ignored) {
                    // ignore
                }
            }
        }
    }

    private static Map<String, String> toSingleValueMap(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> raw = request.getParameterMap();
        for (Map.Entry<String, String[]> e : raw.entrySet()) {
            String[] v = e.getValue();
            if (v == null || v.length == 0) {
                params.put(e.getKey(), "");
            } else if (v.length == 1) {
                params.put(e.getKey(), v[0]);
            } else {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < v.length; i++) {
                    if (i > 0) {
                        sb.append(',');
                    }
                    sb.append(v[i]);
                }
                params.put(e.getKey(), sb.toString());
            }
        }
        return params;
    }

    /**
     * 每 2 分钟执行一次：拉取近期待支付单，逐笔查第三方并更新状态（需开启 payment.sync.enabled）
     */
    @Scheduled(fixedDelayString = "${payment.sync.interval-ms:120000}")
    public void syncPaymentStatus() {
        if (!paymentSyncEnabled) {
            return;
        }
        log.info("商户支付同步：本批时间={}", new Date().getTime());
        // 待启用：按 MerchantPaymentOrder 查单并回写状态，可注入 MerchantPaymentOrderService、MerchantPaymentStrategyFactory
    }
}
