package com.zcxk.xxljob.jobs;
import com.alibaba.fastjson.JSON;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.zcxk.core.utils.DateUtil;
import com.zcxk.rmcp.api.dto.measurementsettlement.MeasurementSettlementDto;
import com.zcxk.rmcp.api.vo.MeterReadRecordVo;
import com.zcxk.rmcp.core.dao.DeviceMapper;
import com.zcxk.rmcp.core.dao.MeasurementInstanceMapper;
import com.zcxk.rmcp.core.dao.MeasurementRecordMapper;
import com.zcxk.rmcp.core.dao.MeasurementSettlementMapper;
import com.zcxk.rmcp.core.dao.mongo.MeterReadRecordDao;
import com.zcxk.rmcp.core.entity.Device;
import com.zcxk.rmcp.core.entity.MeasurementInstance;
import com.zcxk.rmcp.core.entity.MeasurementRecord;
import com.zcxk.rmcp.core.entity.MeasurementSettlement;
import com.zcxk.rmcp.core.mongo.MeterReadRecord;
import com.zcxk.xxljob.dto.MeterReadRecordDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
/**
 *
 * @author heyumin
 * @date 2021-07-30 9:44
 */
@Slf4j
@Component
public class MeasurementSettlementRecordHander {
    @Resource
    MeterReadRecordDao meterReadRecordDao;
    @Resource
    MeasurementRecordMapper measurementRecordMapper;
    @Resource
    MeasurementInstanceMapper measurementInstanceMapper;
    @Resource
    MeasurementSettlementMapper measurementSettlementMapper;
    @Resource
    DeviceMapper deviceMapper;
    int theDeviceDoesNotStart=5;
    private String dateFormat="yyyyMMdd";
    @XxlJob("measurementHandler")
    public ReturnT<String> execute(String info) {
        log.info("开始执行分发任务");
        try {
            MeasurementSettlementDto measurementSettlement=JSON.parseObject(info,MeasurementSettlementDto.class);
            List<Device> devices = deviceMapper.findMeasurementDevice(measurementSettlement);
            MeasurementInstance measurementInstance = addMeasurementInstance(measurementSettlement, devices.size());
            MeasurementSettlement updateTotal=new MeasurementSettlement();
            updateTotal.setId(measurementSettlement.getId());
            updateTotal.setTotalWaterMeters(devices.size());
            measurementSettlementMapper.update(updateTotal);
            List<MeasurementRecord> items = new ArrayList<>();
            Date date=new Date();
            for(Device device : devices) {
                MeasurementRecord item = createClearingRecordItem(device,measurementSettlement,date,
                        measurementInstance.getId());
                items.add(item);
                // 每一千次做一次批量插入
                if(items.size() % 1000 == 0) {
                    measurementRecordMapper.batchInsert(items);
                    items.clear();
                }
            }
            if(!CollectionUtils.isEmpty(items)) {
                measurementRecordMapper.batchInsert(items);
                items.clear();
            }

        }catch (Exception e){
            e.printStackTrace();
        }


        return ReturnT.SUCCESS;
    }
    private MeasurementInstance addMeasurementInstance(MeasurementSettlementDto measurementSettlement,int total){
        MeasurementInstance measurementInstance=new MeasurementInstance();
        measurementInstance.setPlanid(measurementSettlement.getId());
        measurementInstance.setTotalWaterMeters(total);
        measurementInstance.setCreateBy("admin");
        measurementInstance.setCreateDate(new Date());
        Date date=new Date();
        Integer clearingPeriod = measurementSettlement.getBillingCycle();
        Date clearingEndDate = getClearingEndDate(date);
        Date clearingStartDate = getClearingStartDate(clearingEndDate,clearingPeriod);
        measurementInstance.setClearingDay(Integer.parseInt(DateUtil.formatDate(date, dateFormat)));
        measurementInstance.setClearingStartDate(clearingStartDate);
        measurementInstance.setClearingEndDate(clearingEndDate);
        measurementInstance.setNumberOfWaterMetersReviewed(0);
        measurementInstance.setStatus(1);
        measurementInstanceMapper.insert(measurementInstance);
        return measurementInstance;
    }
    protected Date getClearingEndDate(Date clearingDate ) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(clearingDate);
        calendar.add(Calendar.DATE, -1);
        return  calendar.getTime();

    }
    protected Date getClearingStartDate(Date endDate ,Integer period) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(endDate);
        calendar.add(Calendar.MONTH, period*-1);
        return calendar.getTime();

    }

    private MeasurementRecord createClearingRecordItem(Device device ,MeasurementSettlementDto measurementSettlement,Date clearingDate,Integer clearingRecordId) {
        MeasurementRecord item = new MeasurementRecord();
        item.setDeviceId(device.getId());
        item.setPlanId(clearingRecordId);
        item.setMeterNo(device.getMeterNo());
        item.setFileMeterNo(device.getFileNo());
        item.setApprovalStatus("0");
        item.setLocation(device.getAddress());
        item.setStatus(1);
        item.setCreateDate(new Date());
        item.setCreateBy("admin");
        // 1,获取上次结算记录
        MeasurementRecord lastClearingRecordItem = getDeviceLastClearingRecordItem(device,measurementSettlement,clearingDate);
        // 2,获取结算周期内的数据
        Integer clearingPeriod = measurementSettlement.getBillingCycle();
        Date clearingEndDate = getClearingEndDate(clearingDate);
        Date clearingStartDate = getClearingStartDate(clearingEndDate,clearingPeriod);
        List<MeterReadRecord> recordList = meterReadRecordDao.querySettlementWaterConsumption(device,clearingStartDate,clearingEndDate);
        // 3,获取结算周期内开始数据
        MeterReadRecordDTO clearingStartMeterRecord = getClearingStartMeterRecord(device,clearingStartDate,lastClearingRecordItem,recordList);
        item.setLastReading(clearingStartMeterRecord.getReadData()+"");
        item.setLastPeriodDate(clearingStartMeterRecord.getReadDateTime());
        // 4,获取结算周期内结束数据
        MeterReadRecordDTO clearingEndMeterRecord = getClearingEndMeterRecord(device,clearingEndDate,lastClearingRecordItem,recordList);
        item.setCurrentReading(clearingEndMeterRecord.getReadData()+"");
        item.setCurrentPeriodDate(clearingEndMeterRecord.getReadDateTime());
        // 5,计算用水量,本期-上期
        double currenntWsv = Double.parseDouble(item.getCurrentReading());
        double lastWsv = Double.parseDouble(item.getLastReading());
        item.setWaterConsumption(currenntWsv-lastWsv);
        return item ;
    }
    /**
     *  获取设备上一次结算的数据
     * @param device
     * @param clearingPlan
     * @param clearingDate
     * @return
     */
    protected MeasurementRecord getDeviceLastClearingRecordItem(Device device ,MeasurementSettlementDto clearingPlan,Date clearingDate ) {
        // 1,获取上次的结算记录
        Date lastClearingDate = getLastClearingDate(clearingDate,clearingPlan.getBillingCycle());
        Integer lastClearingDay = Integer.parseInt(DateFormatUtils.format(lastClearingDate, dateFormat));
        MeasurementInstance lastClearingRecord = measurementInstanceMapper.findClearingRecord(clearingPlan.getId(), lastClearingDay);
        if(lastClearingRecord == null) {
            return null ;
        }
        else {
            return measurementRecordMapper.findClearingRecordItem(device.getId(), lastClearingRecord.getId());

        }
    }
    /**
     * 获取上次结算日期
     * @param clearingDate
     * @param period
     * @return
     */
    protected Date getLastClearingDate(Date clearingDate ,Integer period ) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(clearingDate);
        calendar.add(Calendar.MONTH, period*-1);
        return calendar.getTime();

    }
    /**
     * 获取结算开始日期的抄表数据
     * @param device 设备
     * @param clearingStartDate 本次月结开始时间
     * @param lastItem 上次月结数据
     * @param
     * @return
     */
    protected MeterReadRecordDTO getClearingStartMeterRecord(Device device,Date clearingStartDate ,MeasurementRecord lastItem,List<MeterReadRecord> records) {
        MeterReadRecordDTO r = new MeterReadRecordDTO();
        // 设备为未启动则直接设置为 0
        if(device.getDeviceStatus()==theDeviceDoesNotStart) {
            r.setReadDateTime(clearingStartDate);
            r.setReadData(0d);
        }
        else {
            // 将上期抄表止度作为本期抄表开始起度
            if(lastItem != null) {
                r.setReadDateTime(lastItem.getCurrentPeriodDate());
                r.setReadData(Double.valueOf(lastItem.getCurrentReading()));
            }
            // 没有上一期数据则取距离结算开始日期最近的数据
            else {
                List<MeterReadRecordVo> mrs = meterReadRecordDao.queryDeviceMeterReadRecordWithCondtion(
                        device.getId(), Integer.parseInt(DateUtil.formatDate(clearingStartDate, dateFormat))
                );
                // 获取不到数据,从取距离结算结束日期最远的数据
                if(CollectionUtils.isEmpty(mrs)  ) {
                    if(CollectionUtils.isEmpty(records)) {
                        r.setReadDateTime(clearingStartDate);
                        r.setReadData(0d);
                    }
                    else {
                        MeterReadRecord mr = records.get(records.size() - 1);
                        r.setReadDateTime(new Date(mr.getData().get(0).getReadTime()));
                        r.setReadData(mr.getData().get(0).getReadData());
                    }
                }
                else {
                    MeterReadRecordVo mr = mrs.get(0);
                    r.setReadDateTime(new Date(mr.getData().getReadTime()));
                    r.setReadData(mr.getData().getReadData());
                }
            }
        }
        return r;
    }
    /**
     *  获取结算结束日期的抄表数据
     * @param device 设备
     * @param clearingEndDate 本次月结结束时间
     * @param lastItem 上次月结数据
     * @param
     * @return
     */
    protected MeterReadRecordDTO getClearingEndMeterRecord(Device device,Date clearingEndDate ,MeasurementRecord lastItem,List<MeterReadRecord> records) {
        MeterReadRecordDTO r = new MeterReadRecordDTO();
        // 设备为未启动则直接设置为 0
        if(device.getDeviceStatus() == theDeviceDoesNotStart) {
            r.setReadDateTime(clearingEndDate);
            r.setReadData(0d);
        }
        else {
            // 本期结算周期内无数据,则直接取上期的结束数据
            if(CollectionUtils.isEmpty(records)) {
                if(lastItem != null) {
                    r.setReadDateTime(lastItem.getCurrentPeriodDate());
                    r.setReadData(Double.valueOf(lastItem.getCurrentReading()));
                }
                // 无上期数据时，则取距离结算结束日期最近的数据
                else {
                    List<MeterReadRecordVo> mrs = meterReadRecordDao.queryDeviceMeterReadRecordWithCondtion( device.getId()
                            , Integer.parseInt(DateUtil.formatDate(clearingEndDate, dateFormat)));
                    if(CollectionUtils.isEmpty(mrs)) {
                        r.setReadDateTime(clearingEndDate);
                        r.setReadData(0D);
                    }
                    else {
                        MeterReadRecordVo mr = mrs.get(0);
                        r.setReadDateTime(new Date(mr.getData().getReadTime()));
                        r.setReadData(mr.getData().getReadData());
                    }
                }
            }
            // 取结算周期内距离结算结束日期最近的数据
            else {
                MeterReadRecord mr = records.get(0);
                r.setReadDateTime(new Date(mr.getData().get(0).getReadTime()));
                r.setReadData(mr.getData().get(0).getReadData());
            }
        }
        return r ;
    }
}
