package com.yeejoin.amos.boot.module.elevator.biz.job;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.module.elevator.api.entity.ElevatorSynLog;
import com.yeejoin.amos.boot.module.elevator.api.mapper.ElevatorMapper;
import com.yeejoin.amos.boot.module.elevator.biz.service.impl.ESElevatorServiceImpl;
import com.yeejoin.amos.boot.module.elevator.biz.service.impl.ElevatorSynLogServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.util.List;
import java.util.Map;

@Component
@RequiredArgsConstructor
@Slf4j
public class SynElevator2EsJob {

    private final ElevatorMapper elevatorMapper;

    private final ESElevatorServiceImpl esElevatorService;

    private final ElevatorSynLogServiceImpl elevatorSynLogService;

    @Scheduled(cron = "${elevator.syn.insert.job.cron:0 0 2 * * ?}")
    @SchedulerLock(name = "synElevator2Es", lockAtMostFor = "PT1H")
    public void synElevator2Es() {
        // 1.获取最新版本号及创建/更新当天的同步日志
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ElevatorSynLog synLog = getOrCreateSynLog();
        try {
            // 2.循环写入或者更新数据
            Page<Map<String, Object>> page = new Page<>(0, 1000);
            page = elevatorMapper.selectElevatorOfIntoManage(page, synLog.getVersion());
            long allPages = page.getPages();
            while (allPages > 0) {
                allPages--;
                Page<Map<String, Object>> result = elevatorMapper.selectElevatorOfIntoManage(page, synLog.getVersion());
                List<Map<String, Object>> elevators = result.getRecords();
                esElevatorService.saveEsElevator2ES(elevators, synLog.getVersion());
            }
            // 3.非最新版本号es索引数据删除及更新同步日志
            this.clearNoUsingEsDataAndUpLog(synLog);
        } catch (Exception e) {
           log.error(e.getMessage(), "elev同步数据失败");
            synLog.setRemark(e.getMessage());
            elevatorSynLogService.updateById(synLog);
        }
        stopWatch.stop();
        log.info("本次同步数据耗时：{}秒,数据详情：{}", stopWatch.getTotalTimeSeconds(), JSONObject.toJSONString(synLog));
    }

    /**
     * 清除不满足条件的电梯及更新同步日志
     *
     * @param synLog 同步日志
     */
    private void clearNoUsingEsDataAndUpLog(ElevatorSynLog synLog) {
        synLog.setAfterNum(esElevatorService.getESElavtorRepository().countByVersion(synLog.getVersion()));
        // 删掉非最新版本号数据
        esElevatorService.getESElavtorRepository().deleteByVersionIsNot(synLog.getVersion());
        synLog.setDeleteNum(synLog.getAfterNum() - synLog.getBeforeNum());
        elevatorSynLogService.updateById(synLog);
    }

    private ElevatorSynLog getOrCreateSynLog() {
        // 兼容处理 支持本天同步多次也支持按照天同步， 当天有记录则使用当天的版本号，否则按照最近日期取版本号
        ElevatorSynLog daySynLog = elevatorSynLogService.getOneBySynDate(DateUtil.date());
        if (daySynLog == null) {  // 当天第一次同步逻辑
            daySynLog = new ElevatorSynLog();
            daySynLog.setSynDate(DateUtil.date());
            daySynLog.setSynTime(DateUtil.date());
            setIntStatisNum(daySynLog);
            setVersion(daySynLog);
            elevatorSynLogService.save(daySynLog);
        } else {            //   当天非首次同步逻辑
            daySynLog.setBeforeNum(esElevatorService.getESElavtorRepository().count());
            daySynLog.setVersion(daySynLog.getVersion() + 1);
            daySynLog.setSynTime(DateUtil.date());
            daySynLog.setRemark("");
            elevatorSynLogService.updateById(daySynLog);
            return daySynLog;
        }
        return daySynLog;
    }

    private void setVersion(ElevatorSynLog synLog) {
        ElevatorSynLog lastDaySynLog = elevatorSynLogService.getOneBySynDateLess(DateUtil.date());
        if (lastDaySynLog != null) {
            synLog.setVersion(lastDaySynLog.getVersion() == null ? 1 : lastDaySynLog.getVersion() + 1);
        } else {
            synLog.setVersion(10L);
        }
    }

    private void setIntStatisNum(ElevatorSynLog synLog) {
        synLog.setAfterNum(0L);
        synLog.setDeleteNum(0L);
        synLog.setBeforeNum(esElevatorService.getESElavtorRepository().count());
    }

}
