package com.docus.server.collect.report.service.impl;

import com.docus.core.util.Func;
import com.docus.infrastructure.redis.service.IdService;
import com.docus.log.annotation.TrackRetryListener;
import com.docus.server.archivefile.infrastructure.entity.AfCollectTask;
import com.docus.server.archivefile.infrastructure.entity.AfReportRecord;
import com.docus.server.archivefile.infrastructure.mapper.AfCollectTaskMapper;
import com.docus.server.archivefile.infrastructure.mapper.AfReportRecordMapper;
import com.docus.server.collect.report.event.TaskConsumptionReportDownEvent;
import com.docus.server.collect.report.event.ThreePartyPushReportDownEvent;
import com.docus.server.collect.report.service.IReportService;
import com.docus.server.archivefile.infrastructure.dto.ReportDTO;
import com.docus.server.record.mapper.TBasicMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 报告服务实现类
 *
 * @author wyb
 */
@Slf4j
@Service
public class ReportServiceImpl implements IReportService {

    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private AfCollectTaskMapper collectTaskMapper;
    @Resource
    private AfReportRecordMapper afReportRecordMapper;
    @Resource
    private TBasicMapper tBasicMapper;
    @Resource
    private IdService idService;

    @Override
    @TrackRetryListener("report")
    public void report(ReportDTO reportDTO) {
        // 系统无视图生成的任务，消费查询的报告
        if (reportDTO.getTaskId() != null) {
            taskConsumptionReport(reportDTO);
        }
        // 第三方推送的报告，任务后生成的
        threePartyPushReports(reportDTO);
    }

    private void taskConsumptionReport(ReportDTO reportDTO) {
        applicationContext.publishEvent(new TaskConsumptionReportDownEvent(this, reportDTO));
        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException ex) {
            log.error(ex.getMessage(), ex);
        }
    }

    private void threePartyPushReports(ReportDTO reportDTO) {
        String patientId = null;
        try {
            // 如果出现多条出错的情况，还是得保存收到的信息，人工干预处理
            patientId = tBasicMapper.getPatientIdByInpatientNoAndAdminssTimes(reportDTO.getInpatientNo(), reportDTO.getAdmisstimes());
        } catch (Exception ex) {
            log.error("查询病案主键出错了", ex);
        }
        // 不验证数据，始终保存收到的信息
        AfReportRecord afReportRecord = afReportRecordMapper.getRecordBySerialnumAndInpatientNoAndSysFlag(reportDTO.getSerialnum(), reportDTO.getInpatientNo(), reportDTO.getAdmisstimes(), reportDTO.getSysFlag());
        if (afReportRecord == null) {
            long id = idService.getDateSeq();
            afReportRecord = new AfReportRecord(reportDTO);
            afReportRecord.setTaskId(id);
            afReportRecord.setPatientId(patientId);
            afReportRecordMapper.saveRecord(afReportRecord);
        } else {
            // 更新 主要更新 url
            afReportRecord.setDownUrl(reportDTO.getDownUrl());
            afReportRecord.setDownType(reportDTO.getDowntype());
            afReportRecord.setFileName(reportDTO.getFileTitle());
            afReportRecord.setPatientId(patientId);
            afReportRecordMapper.updateRecordByTaskId(afReportRecord);
        }
        // 不使用事务，不需要回滚上面的保存

        // 根据记录中的任务id，查询是否需要新增任务
        if (Func.isBlank(patientId)) {
            log.warn("病案号：{}，住院次数：{} 未找到病案基础数据，暂不进行下载任务！", reportDTO.getInpatientNo(), reportDTO.getAdmisstimes());
            return;
        }
        // 判断是否需要保存任务
        AfCollectTask afCollectTask = collectTaskMapper.getTaskById(afReportRecord.getTaskId());
        if (afCollectTask == null) {
            afCollectTask = new AfCollectTask();
            afCollectTask.setId(afReportRecord.getTaskId());
            afCollectTask.setC1(reportDTO.getSerialnum());
            afCollectTask.setC2(reportDTO.getFileTitle());
            afCollectTask.setC3(reportDTO.getJzh());
            afCollectTask.setPatientId(patientId);
            afCollectTask.setSysflag(reportDTO.getSysFlag());
            afCollectTask.setState("0");
            afCollectTask.setPatientId(patientId);
            collectTaskMapper.saveTask(afCollectTask);
        }
        // 都成功后发布下载事件
        applicationContext.publishEvent(new ThreePartyPushReportDownEvent(this, afReportRecord.getTaskId()));
        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException ex) {
            log.error(ex.getMessage(), ex);
        }
    }

    @Override
    public void makeupThreePartyPushReportByTaskIds(List<Long> taskIds) throws Exception {
        if (taskIds == null || taskIds.isEmpty()) {
            return;
        }
        // 定义一批200查询，分批次
        final int oneBatchCount = 200;
        int startIndex = 0;
        int toIndex = oneBatchCount;
        boolean loop = true;
        do {
            // 获取截取下标
            if (taskIds.size() <= oneBatchCount) {
                toIndex = taskIds.size();
                // 最后一批截取
                loop = false;
            }
            // 截取每一批
            List<Long> makeupTaskIds = taskIds.subList(startIndex, toIndex);
            makeupTaskIds = afReportRecordMapper.getHasPatientIdTaskIdsByTaskIds(makeupTaskIds);
            if (Func.isNotEmpty(makeupTaskIds)) {
                for (Long taskId : makeupTaskIds) {
                    // 发布下载事件
                    applicationContext.publishEvent(new ThreePartyPushReportDownEvent(this, taskId));
                    // 等待防止过快
                    TimeUnit.MILLISECONDS.sleep(50);
                }
            }
            // 当截取长度小于集合长度，可以进行下次循环截取
        } while (loop);
    }
}
