package com.fs.app.taskService.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fs.app.taskService.SopWxLogsService;
import com.fs.common.utils.PubFun;
import com.fs.common.utils.StringUtils;
import com.fs.common.utils.date.DateUtil;
import com.fs.sop.domain.*;
import com.fs.sop.mapper.QwSopTempMapper;
import com.fs.sop.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

@Service
@Slf4j
@AllArgsConstructor
public class SopWxLogsServiceImpl implements SopWxLogsService {

    private final IQwSopService qwSopService;
    private final QwSopTempMapper qwSopTempMapper;
    private final IQwSopTempDayService qwSopTempDayService;
    private final ISopUserLogsWxService sopUserLogsWxService;
    private final IQwSopTempRulesService qwSopTempRulesService;
    private final IQwSopLogsService  qwSopLogsService;

    @Override
    public void wxSopLogsByTime(LocalDateTime now) throws Exception {
        long startTimeMillis = System.currentTimeMillis();
        log.info("====== 开始选择和处理 个微SOP 用户日志 ======");

        List<QwSop> sopList = qwSopService.selectWxSop();
        if(sopList.isEmpty()){
            return;
        }
        CountDownLatch sopGroupLatch = new CountDownLatch(sopList.size());
        sopList.forEach(sop -> {
            processSopGroupAsync(sop, sopGroupLatch, now);
        });
        sopGroupLatch.await();

        long endTimeMillis = System.currentTimeMillis();
        log.info("====== 个微SOP 用户日志处理完成，耗时 {} 毫秒 ======", (endTimeMillis - startTimeMillis));
    }

    private void processSopGroupAsync(QwSop sop, CountDownLatch latch, LocalDateTime now) {
        try {
            processSopGroup(sop, now);
        } catch (Exception e) {
            log.error("处理个微 SOP ID {} 时发生异常: {}", sop.getId(), e.getMessage(), e);
        } finally {
            latch.countDown();
        }
    }

    private void processSopGroup(QwSop sop, LocalDateTime now) {
        // 提前一个小时生成
        LocalDateTime start = now.plusHours(1);
        // 当前小时
        int hour = start.getHour();
        // 获取模板
        QwSopTemp qwSopTemp = qwSopTempMapper.selectQwSopTempById(sop.getTempId());
        // 如果模板为空
        if(qwSopTemp == null){
            log.error("SOP ID：{}没找到模板 {} 跳过生成", sop.getId(), sop.getTempId());
            return;
        }
        // 获取模板下面每一天的数据
        List<QwSopTempDay> dayList = qwSopTempRulesService.listByTempIdAll(sop.getTempId());
        // 更具天数分组
        Map<Long, QwSopTempDay> dayMap = PubFun.listToMapByGroupObject(dayList, e -> e.getDayNum().longValue());
        // 获取sop下面所有的个微营期数据
        List<SopUserLogsWx> wxUserList = sopUserLogsWxService.listBySopId(sop.getId());
        // 循环每一个人的数据，并对数据进行筛选，营期开始时间不能为空，并且要大于当前生成的时间
        wxUserList.stream().filter(e -> e.getStartTime() != null && !e.getStartTime().isAfter(now.toLocalDate())).forEach(sopUserLogsWx -> {
            // 计算营期到现在是第几天
            long until = sopUserLogsWx.getStartTime().until(now.toLocalDate(), ChronoUnit.DAYS) + 1;
            // 是否存在跨天的现象
            if(!now.toLocalDate().equals(start.toLocalDate())){
                until++;
            }
            // 根据第几天获取数据
            QwSopTempDay day = dayMap.get(until);
            // 筛选规则，获得当前一个小时的所有数据
            List<QwSopTempRules> rulesList = day.getList().stream().filter(e -> StringUtils.isNotEmpty(e.getTime()) && LocalTime.parse(e.getTime()).getHour() == hour).collect(Collectors.toList());
            // 创建发送记录
            List<QwSopLogs> losList = rulesList.stream().map(rules -> {
                LocalTime time = LocalTime.parse(rules.getTime());
                return createBaseLog(LocalDateTime.of(start.toLocalDate(), time), sop, sopUserLogsWx, rules);
            }).collect(Collectors.toList());
            // 保存记录
            qwSopLogsService.batchInsertQwSopLogs(losList);
        });

    }


    private QwSopLogs createBaseLog(LocalDateTime sendTime, QwSop sop, SopUserLogsWx wx, QwSopTempRules rules) {
        QwSopLogs sopLogs = new QwSopLogs();
        sopLogs.setSendTime(DateUtil.formatLocalDateTime(sendTime));
        sopLogs.setExpirationTime(DateUtil.formatLocalDateTime(sendTime.plusHours(sop.getExpiryTime())));
        sopLogs.setQwUserid(wx.getAccountId().toString());
        sopLogs.setLogType(1);
        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(rules));
        jsonObject.remove("settingList");
        jsonObject.remove("list");
        jsonObject.put("setting", rules.getSettingList());
        sopLogs.setContentJson(jsonObject.toJSONString());
        sopLogs.setSendType(sop.getSendType());
        sopLogs.setSendStatus(3L);
        sopLogs.setReceivingStatus(0L);
        sopLogs.setSopId(sop.getId());
        sopLogs.setExternalUserName(wx.getUserWxName());
        sopLogs.setCorpId(sop.getCorpId());
        sopLogs.setCompanyId(sop.getCompanyId());
        return sopLogs;
    }
}
