package com.jeesharp.business.modules.pay.paysubmerchantapplyment.support;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.pay.core.IJPayHttpResponse;
import com.jeesharp.framework.log.api.constant.InterfaceLogResultConstant;
import com.jeesharp.framework.log.api.entity.InterfaceLogEntity;
import com.jeesharp.framework.log.api.mapper.InterfaceLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 微信进件等外部请求写入框架 {@link InterfaceLogEntity}（表 {@code interface_log}）。
 *
 * @author jeesharp
 * @since 2026-06-12
 */
@Slf4j
@Component
public class PayWechatInterfaceLogRecorder {

    private static final int MAX_TEXT_LEN = 60000;

    private final InterfaceLogMapper interfaceLogMapper;
    private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();

    public PayWechatInterfaceLogRecorder(@Autowired(required = false) InterfaceLogMapper interfaceLogMapper) {
        this.interfaceLogMapper = interfaceLogMapper;
    }

    /**
     * 组装待写入的接口日志实体（调用方在请求前后补全响应字段）。
     */
    public InterfaceLogEntity begin(String scenarioType, String httpMethod, String requestUrl, String requestParam,
                                   String businessId, String remark) {
        InterfaceLogEntity entity = new InterfaceLogEntity();
        entity.setId(IdUtil.fastSimpleUUID());
        entity.setScenarioType(scenarioType);
        entity.setHttpMethod(httpMethod);
        entity.setRequestUrl(requestUrl);
        entity.setRequestParam(truncate(requestParam));
        entity.setBusinessId(StrUtil.blankToDefault(businessId, null));
        entity.setRemark(StrUtil.blankToDefault(remark, null));
        entity.setRequestTime(new Date());
        return entity;
    }

    public void completeSuccess(InterfaceLogEntity entity, IJPayHttpResponse response, long startMs) {
        fillResponse(entity, response, startMs);
        entity.setResponseStatus(InterfaceLogResultConstant.SUCCESS);
    }

    public void completeHttpFail(InterfaceLogEntity entity, IJPayHttpResponse response, long startMs, String errorMessage) {
        fillResponse(entity, response, startMs);
        entity.setResponseStatus(InterfaceLogResultConstant.FAIL);
        entity.setErrorMessage(truncate(errorMessage));
    }

    public void completeError(InterfaceLogEntity entity, long startMs, String errorMessage) {
        entity.setResponseTime(new Date());
        entity.setDuration(System.currentTimeMillis() - startMs);
        entity.setResponseStatus(InterfaceLogResultConstant.ERROR);
        entity.setErrorMessage(truncate(errorMessage));
    }

    /**
     * 异步落库；未装配 {@link InterfaceLogMapper} 时仅打 debug 日志。
     */
    public void saveAsync(InterfaceLogEntity entity) {
        if (entity == null) {
            return;
        }
        if (interfaceLogMapper == null) {
            log.debug("InterfaceLogMapper 未装配，跳过接口日志落库: {}", entity.getRequestUrl());
            return;
        }
        if (entity.getCreateDate() == null) {
            entity.setCreateDate(new Date());
        }
        executor.execute(() -> {
            try {
                interfaceLogMapper.insert(entity);
            } catch (Exception e) {
                log.warn("保存微信进件接口日志失败, url={}", entity.getRequestUrl(), e);
            }
        });
    }

    private static void fillResponse(InterfaceLogEntity entity, IJPayHttpResponse response, long startMs) {
        entity.setResponseTime(new Date());
        entity.setDuration(System.currentTimeMillis() - startMs);
        if (response != null) {
            entity.setHttpStatusCode(response.getStatus());
            entity.setResponseResult(truncate(response.getBody()));
        }
    }

    private static String truncate(String text) {
        if (text == null) {
            return null;
        }
        if (text.length() <= MAX_TEXT_LEN) {
            return text;
        }
        return text.substring(0, MAX_TEXT_LEN) + "...[truncated]";
    }
}
