package com.yd.csf.service.audit;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
 * 审计生命周期编排器。
 * 封装 begin → action → success/fail → close 的固定模板，调用方只需编写业务逻辑。
 *
 * <pre>{@code
 * // INSERT 场景
 * return auditTemplate.execute("来佣管理", 1, "导入入账记录", ctx -> {
 *     saveBatch(list);
 *     auditHelper.record("commission", null, toMap(list), ctx);
 *     return true;
 * });
 *
 * // UPDATE 场景
 * return auditTemplate.execute("应付款管理", 2, "生成可出账", ctx -> {
 *     Map<String, ExpectedFortune> before = auditHelper.snapshot(list);
 *     // ... 业务变更 ...
 *     Map<String, ExpectedFortune> after = auditHelper.snapshot(list);
 *     auditHelper.record("expected_fortune", before, after, ctx);
 *     return true;
 * });
 * }</pre>
 *
 * @author Zhang Jianan
 */
@Component
@RequiredArgsConstructor
public class AuditTemplate {

    private final AuditService auditService;

    /**
     * 执行带审计的操作。
     * 自动处理 begin → success → close（正常路径）或 begin → fail → close（异常路径）。
     * 异常会原样重新抛出，不改变异常传播链。
     *
     * @param module       业务模块名称
     * @param businessType 业务类型
     * @param content      操作描述
     * @param action       业务逻辑，接收 AuditContext，返回结果
     * @param <T>          返回值类型
     * @return action 的返回值
     */
    public <T> T execute(String module, Integer businessType,
                         String content, AuditAction<T> action) {
        String requestId = auditService.begin(module, businessType, content);
        try {
            T result = action.apply(AuditContextHolder.get());
            auditService.success(requestId);
            return result;
        } catch (Exception e) {
            auditService.fail(requestId, e.getMessage());
            throw (RuntimeException) e;
        } finally {
            auditService.close(requestId);
        }
    }

    /**
     * 审计操作函数式接口。
     *
     * @param <T> 返回值类型
     */
    @FunctionalInterface
    public interface AuditAction<T> {
        T apply(AuditContext ctx);
    }
}
