package com.cf.imes.framework.organ.core.job;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.organ.core.service.OrganFrameworkService;
import com.cf.imes.framework.organ.core.util.OrganUtils;
import com.xxl.job.core.context.XxlJobHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 多组织 JobHandler AOP
 * 任务执行时，会按照组织逐个执行 Job 的逻辑
 *
 * 注意，需要保证 JobHandler 的幂等性。因为 Job 因为某个组织执行失败重试时，之前执行成功的组织也会再次执行。
 *
 * @author 晨丰科技
 */
@Aspect
@RequiredArgsConstructor
@Slf4j
public class OrganJobAspect {

    private final OrganFrameworkService organFrameworkService;

    @Around("@annotation(organJob)")
    public void around(ProceedingJoinPoint joinPoint, OrganJob organJob) {
        // 获得组织列表
        List<Long> organIds = organFrameworkService.getOrganIds();
        if (CollUtil.isEmpty(organIds)) {
            return;
        }

        // 逐个组织，执行 Job
        Map<Long, String> results = new ConcurrentHashMap<>();
        organIds.parallelStream().forEach(organId -> {
            // TODO 晨丰：先通过 parallel 实现并行；1）多个组织，是一条执行日志；2）异常的情况
            OrganUtils.execute(organId, () -> {
                try {
                    joinPoint.proceed();
                } catch (Throwable e) {
                    results.put(organId, ExceptionUtil.getRootCauseMessage(e));
                    // 打印异常
                    XxlJobHelper.log(StrUtil.format("[多组织({}) 执行任务({})，发生异常：{}]",
                            organId, joinPoint.getSignature(), ExceptionUtils.getStackTrace(e)));
                }
            });
        });
        // 如果 results 非空，说明发生了异常，标记 XXL-Job 执行失败
        if (CollUtil.isNotEmpty(results)) {
            XxlJobHelper.handleFail(JsonUtils.toJsonString(results));
        }
    }

}
