package com.cpop.oam.framework.tasks;

import com.cpop.api.cloudDb.core.dto.CloudStoreActiveDto;
import com.cpop.api.cloudDb.handler.CloudStoreHandler;
import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.table.SysConfig;
import com.cpop.core.service.CoreService;
import com.cpop.core.service.RedisService;
import com.cpop.core.utils.SpringUtils;
import com.cpop.jambox.business.entity.StoreActive;
import com.cpop.jambox.business.service.StoreActiveService;
import com.cpop.oam.business.entity.Clue;
import com.cpop.oam.business.entity.ClueRecord;
import com.cpop.oam.business.entity.DataImport;
import com.cpop.oam.business.entity.Task;
import com.cpop.oam.business.entity.table.DataImportTableDef;
import com.cpop.oam.business.mapper.ClueMapper;
import com.cpop.oam.business.service.*;
import com.cpop.oam.business.vo.SignGoalConfigInfoVo;
import com.cpop.oam.business.vo.StaffInfoVo;
import com.cpop.oam.framework.constant.OamConfigKey;
import com.cpop.oam.framework.constant.WebHookKeyConstant;
import com.cpop.oam.framework.enums.OamConfigEnum;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.update.UpdateChain;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

import static com.cpop.oam.business.entity.table.ClueTableDef.CLUE;
import static com.cpop.oam.business.entity.table.TaskTableDef.TASK;
import static com.cpop.system.business.entity.table.StoreTableDef.STORE;


/**
 * @author DB
 * @createTime 2023/11/22 18:07
 * @description
 */
@Slf4j
@Configuration
@Profile("prod")
public class OamScheduledTasks {

    @Autowired
    private DutyService dutyService;

    /**
     * @descriptions 每天9点通知值班人员
     * @author DB
     * @date 2023/11/22 18:08
     * @return: void
     */
    @Scheduled(cron = "0 0 9 * * *")
    public void dutyNotice() {
        dutyService.dutyNotice();
    }

    /**
     * 凌晨20分同步导入的数据
     * @author DB
     * @since 2023/12/10
     */
    @Scheduled(cron = "0 20 0 * * *")
    public void syncImportData() throws InterruptedException {
        log.info("==============开始同步校区数据===========");
        long start = System.currentTimeMillis();
        DataImportService dataImportService = SpringUtils.getBean(DataImportService.class);
        List<DataImport> dataList = dataImportService.queryChain()
                .where(DataImportTableDef.DATA_IMPORT.IMPORT_STATUS.eq(false)).list();
        for (DataImport item : dataList) {
            SpringUtils.getBean(DataImportAsyncTask.class).asyncUpdateShoppingCartAmount(item);
            Thread.sleep(600000);
        }
        long end = System.currentTimeMillis();
        log.info("同步校区数据执行时间：{}ms", end - start);
    }

    /**
     * 检查任务是否逾期
     * @author DB
     * @since 2023/12/11
     */
    @Scheduled(cron = "0 10 0 * * *")
    public void checkTaskWhetherFinish() {
        log.info("==============开始检查进行中任务===========");
        TaskService taskService = SpringUtils.getBean(TaskService.class);
        List<Task> taskList = taskService.queryChain().where(TASK.TASK_STATUS.in(2, 3)).and(TASK.TASK_TYPE.in(0, 1)).list();
        List<Task> filterList = taskList.stream().filter(item -> item.getExpectedCompletionDate().plusDays(1).isBefore(LocalDate.now())).collect(Collectors.toList());
        if (!filterList.isEmpty()) {
            //任务项逾期
            taskService.updateChain().set(TASK.TASK_ITEM, -1).where(TASK.ID.in(filterList.stream().map(Task::getId).collect(Collectors.toSet()))).update();
        }
    }

    /**
     * 凌晨30分检查线索是否脱离
     * @author DB
     * @since 2023/12/10
     */
    @Scheduled(cron = "0 30 0 * * *")
    @Transactional(rollbackFor = Exception.class)
    public void checkClue() {
        log.info("==============开始检查线索数据===========");
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        CoreService coreService = SpringUtils.getBean(CoreService.class);
        CommonService commonService = SpringUtils.getBean(CommonService.class);
        Map<String, String> configMap = new HashMap<>(8);
        Arrays.asList(OamConfigKey.SIGN_GOAL).forEach(item -> {
            String cacheInfo = redisService.getCacheObject(commonService.getCacheKey(item));
            if (StringUtils.isNotBlank(cacheInfo)) {
                // 获取枚举
                OamConfigEnum sysConfigEnum = OamConfigEnum.matchKey(item);
                configMap.put(sysConfigEnum.getField(), cacheInfo);
            } else {
                // 查询系统
                SysConfig sysConfig = coreService.selectConfigByKey(item);
                if (null != sysConfig) {
                    // 获取枚举
                    OamConfigEnum sysConfigEnum = OamConfigEnum.matchKey(item);
                    configMap.put(sysConfigEnum.getField(), sysConfig.getConfigValue());
                }
            }
        });
        SignGoalConfigInfoVo signGoalConfigInfoVo = new SignGoalConfigInfoVo();
        BeanUtils.mapToObj(configMap, signGoalConfigInfoVo);
        //设置了线索指标
        if (StringUtils.isNotBlank(signGoalConfigInfoVo.getSignInterval())&&StringUtils.isNotBlank(signGoalConfigInfoVo.getFollowUpInterval())){
            //查询所有有负责人的线索
            ClueService clueService = SpringUtils.getBean(ClueService.class);
            List<Clue> clueList = clueService.queryChain()
                    .where(CLUE.RESPONSIBLE_STAFF_ID.isNotNull())
                    .and(CLUE.CLUE_STATUS.ne(1))
                    .list();
            if (!clueList.isEmpty()){
                List<Clue> followOffClueList = new ArrayList<>();
                List<Clue> signOffClueList = new ArrayList<>();
                List<Clue> warnClueList = new ArrayList<>();
                LocalDateTime now = LocalDateTime.now();
                clueList.forEach(item->{
                    //对比最后跟进时间
                    Long followInterval = ChronoUnit.DAYS.between(now, item.getLastFollowUpTime());
                    //对比最后跟进时间
                    Long signInterval = ChronoUnit.DAYS.between(LocalDateTime.now(), item.getReceiptTime());
                    if (followInterval.intValue() - Integer.parseInt(signGoalConfigInfoVo.getFollowUpInterval()) >= 0) {
                        followOffClueList.add(item);
                    } else if (signInterval.intValue() - Integer.parseInt(signGoalConfigInfoVo.getSignInterval()) >= 0) {
                        signOffClueList.add(item);
                    } else if (followInterval.intValue() - 5 <= 0) {
                        //跟进警告
                        warnClueList.add(item);
                    } else if (signInterval.intValue() - 10 <= 0) {
                        // 签约警告
                        warnClueList.add(item);
                    }
                });
                List<ClueRecord> clueRecords = new ArrayList<>();
                //跟进脱离
                if (!followOffClueList.isEmpty()){
                    followOffClueList.forEach(item->{
                        ClueRecord clueRecord = new ClueRecord();
                        clueRecord.setClueId(item.getId())
                                .setRecordStaffId("1")
                                .setRecordType(4)
                                .setRecordContent("跟进间隔过长");
                        clueRecords.add(clueRecord);
                    });
                    Db.executeBatch(signOffClueList, ClueMapper.class, (mapper, clue) -> {
                        UpdateChain.of(mapper)
                                .set(CLUE.RECEIPT_TIME, null)
                                .set(CLUE.RESPONSIBLE_STAFF_ID, null)
                                .set(CLUE.CLUE_STATUS, 0)
                                .where(CLUE.ID.eq(clue.getId()))
                                .update();
                    });
                }
                //签约脱离
                if (!signOffClueList.isEmpty()){
                    signOffClueList.forEach(item->{
                        ClueRecord clueRecord = new ClueRecord();
                        clueRecord.setClueId(item.getId())
                                .setRecordStaffId("1")
                                .setRecordType(4)
                                .setRecordContent("签约周期过长");
                        clueRecords.add(clueRecord);
                    });
                    Db.executeBatch(signOffClueList, ClueMapper.class, (mapper, clue) -> {
                        UpdateChain.of(mapper)
                                .set(CLUE.RECEIPT_TIME, null)
                                .set(CLUE.RESPONSIBLE_STAFF_ID, null)
                                .set(CLUE.CLUE_STATUS, 0)
                                .where(CLUE.ID.eq(clue.getId()))
                                .update();
                    });
                    clueService.updateBatch(signOffClueList);
                }
                //签约脱离
                if (!warnClueList.isEmpty()) {
                    warnClueList.forEach(item -> {
                        item.setClueStatus(2);
                    });
                    clueService.updateBatch(warnClueList);
                }
                if (!clueRecords.isEmpty()){
                    //保存记录
                    SpringUtils.getBean(ClueRecordService.class).saveBatch(clueRecords);
                }
            }
        }
    }

    /**
     * 任务逾期提醒
     * @author DB
     * @since 2023/12/11
     */
    @Scheduled(cron = "0 30 9 * * *")
    public void taskOverdueRemind() {
        log.info("==============开始检查即将逾期任务===========");
        TaskService taskService = SpringUtils.getBean(TaskService.class);
        //进行中的任务提醒任务负责人
        List<Task> dealTasks = taskService.queryChain().where(TASK.TASK_STATUS.eq(2)).and(TASK.TASK_TYPE.in(0, 1)).and(TASK.EXPECTED_COMPLETION_DATE.eq(LocalDate.now())).list();
        if (!dealTasks.isEmpty()) {
            dealTasks.forEach(item->{
                ArrayList<String> phoneList = new ArrayList<>();
                StaffInfoVo staffInfo = SpringUtils.getBean(StaffService.class).getStaffInfo(item.getResponsibleStaffId());
                phoneList.add(staffInfo.getPhoneNumber());
                try {
                    SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.PRODUCT_BOT, phoneList,
                                    "==========您有一个任务今天即将到期,请及时处理==========\n" + item.getTaskContent(),
                                    false);
                } catch (IOException e) {
                    throw new ServiceException("发送消息通知失败!");
                }
            });
        }
        List<Task> testTasks = taskService.queryChain().where(TASK.TASK_STATUS.eq(3)).and(TASK.TASK_TYPE.in(0, 1)).and(TASK.EXPECTED_COMPLETION_DATE.eq(LocalDate.now().minusDays(1))).list();
        if (!testTasks.isEmpty()) {
            String testStaffPhones = SpringUtils.getBean(RedisService.class).getCacheObject(OamConfigKey.OAM_CONFIG_KEY + OamConfigEnum.TEST_STAFF_PHONE.getKey());
            testTasks.forEach(item->{
                ArrayList<String> phoneList = new ArrayList<>();
                phoneList.add(testStaffPhones);
                try {
                    SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.PRODUCT_BOT, phoneList,
                            "==========您有一个测试任务今天即将到期,请及时处理==========\n" + item.getTaskContent(),
                            false);
                } catch (IOException e) {
                    throw new ServiceException("发送消息通知失败!");
                }
            });
        }
    }

    /**
     * 每天晚上1点40或前天校区活跃数
     * @author DB
     * @since 2024/4/12
     */
    @Scheduled(cron = "0 40 1 * * *")
    public void getStoreActivityData(){
        LocalDate date = LocalDate.now().minusDays(1);
        List<CloudStoreActiveDto> storeActiveData = SpringUtils.getBean(CloudStoreHandler.class).getStoreActiveData(date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        List<StoreActive> storeActives = BeanUtils.mapToList(storeActiveData, StoreActive.class);
        if (!storeActives.isEmpty()){
            storeActives.forEach(item->{
                item.setActiveDate(date);
            });
            SpringUtils.getBean(StoreActiveService.class).saveBatch(storeActives);
        }

    }
}
