package com.sw.mes.sap.reconciliation.framework;

import cc.cczn.matrix.common.monitor.RecordLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 对账任务框架的实现类：
 * 1、把请求结果做聚合
 * 2、增加日志记录
 *
 * @Author：wanjia
 * @Date：2024/2/26 11:30
 */
@Slf4j
@Component
public class ReconciliationImpl implements Reconciliation {

    private final ExecutorService threadPool = Executors.newFixedThreadPool(10);

    @Override
    public <R, T> ReconResult checkById(String bizName, Serializable id, CrossComparison<R, T> crossComparison, FetchData<T>... fetchDataList) {
        CountDownLatch latch = new CountDownLatch(fetchDataList.length);
        List<Future<IntermediateResult<T>>> futureList = new ArrayList<>(fetchDataList.length);
        for (FetchData fetchData : fetchDataList) {
            // 获取主线程中的请求信息
            RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
            Future<IntermediateResult<T>> future = threadPool.submit(() -> {
                RequestContextHolder.setRequestAttributes(attributes);
                try {
                    IntermediateResult<T> result = fetchData.fetch(id);
                    latch.countDown();
                    return result;
                } finally {
                    RequestContextHolder.resetRequestAttributes();
                }
            });
            futureList.add(future);
        }
        List<IntermediateResult<T>> intermediateResults = new ArrayList<>(fetchDataList.length);
        try {
            boolean await = latch.await(30, TimeUnit.SECONDS);
            if (!await) {
                log.error("查询超时，10s未返回结果...");
            }
            for (Future<IntermediateResult<T>> future : futureList) {
                IntermediateResult<T> result = future.get();
                if (null == result) {//如果返回结果为null，则不往后端传递，这样后端可以直接判断length来判断数据是否可行
                    RecordLogger.warn("[" + bizName + ":" + id + "],feature.get == null");
                    continue;
                }
                intermediateResults.add(result);
            }
        } catch (InterruptedException e) {
            log.error("error in fetch data..", e);
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            log.error("error in execution..", e);
            throw new RuntimeException(e);
        }
        ReconResult result = crossComparison.comparison(null, intermediateResults.toArray(new IntermediateResult[fetchDataList.length]));
        RecordLogger.warn("[" + bizName + ":" + id + "] " + result.toString());
        return result;
    }

    @Override
    public <R extends QueryKey, T> void batchScan(String bizName, CrossComparison<R, T> crossComparison, ScanFetchData<R> scanFetch, FetchData<T>... fetchDataList) {
        AtomicInteger count = new AtomicInteger();
        scanFetch.fetch(data -> {
            count.getAndIncrement();
            CountDownLatch latch = new CountDownLatch(fetchDataList.length);
            List<Future<IntermediateResult<T>>> futureList = new ArrayList<>(fetchDataList.length);
            for (FetchData fetchData : fetchDataList) {
                RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
                Future<IntermediateResult<T>> future = threadPool.submit(() -> {
                    RequestContextHolder.setRequestAttributes(attributes);
                    try {
                        IntermediateResult<T> result = fetchData.fetch(data.getQueryKey());
                        latch.countDown();
                        return result;
                    } finally {
                        RequestContextHolder.resetRequestAttributes();
                    }
                });
                futureList.add(future);
            }

            //拉取结果
            List<IntermediateResult<T>> intermediateResults = new ArrayList<>(fetchDataList.length);
            try {
                boolean await = latch.await(30, TimeUnit.SECONDS);
                if (!await) {
                    log.error("查询超时，10s未返回结果...");
                }
                for (Future<IntermediateResult<T>> future : futureList) {
                    IntermediateResult<T> result = future.get();
                    if (null == result) {//如果返回结果为null，则不往后端传递，这样后端可以直接判断length来判断数据是否可行
                        RecordLogger.warn("[" + bizName + ":" + data.getQueryKey() + "],feature.get == null");
                        continue;
                    }
                    intermediateResults.add(result);
                }
            } catch (Exception e) {
                log.error("error in fetch data..", e);
                throw new RuntimeException(e);
            }
            ReconResult result = crossComparison.comparison(data, intermediateResults.toArray(new IntermediateResult[fetchDataList.length]));
            RecordLogger.warn("[" + bizName + ":" + data.getQueryKey() + "] " + result.toString());
        });
        log.error("finish ... with:{}", count.get());
    }
}
