package com.xinxincaravan.caravan.vehicle.biz;

import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.google.common.collect.Maps;
import com.xinxincaravan.caravan.vehicle.constant.RedisKey;
import com.xinxincaravan.caravan.vehicle.entity.VehicleBookInfo;
import com.xinxincaravan.caravan.vehicle.mapper.VehicleBookInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VehicleBookInfoBiz extends BaseBiz<VehicleBookInfoMapper, VehicleBookInfo> {

    public static final String TB_NAME_PREFIX = "vehicle_book_info_his_";
    public static final DateTimeFormatter YEAR_DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyy");
    public static final DateTimeFormatter YEARMONTH_DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyy-MM");
    public static final Integer DEL_BATCH_SIZE = 1000;
    public static final Integer COPY_BATCH_SIZE = 100;

    @Autowired
    private RedisTemplate customRedisTemplate;

    /**
     * 迁移数据到历史表
     * 每年一张表
     */
    @Scheduled(cron = "0 0 0 1 * ?")//每月1号0点触发
    @Transactional
    public void transfer2HistoryTb(){
        //获取表格名称
        String tbName = getTbNameNow();
        DateTime now = DateTime.now();//当前获取的时间为标准
        log.info("开始预定信息迁移至历史表的定时任务。");
        //每月初将上月数据复制到历史表
        Boolean needRun= copyDataLastMoth(now,tbName);
        if(needRun) {
            //每月初将上上月数据从当前信息表中删除
            delDataTheMonthBeforeLast(now, tbName);
        }
    }

    /**
     * 获取上月数据，并复制到历史表
     */
    @Transactional
    public Boolean copyDataLastMoth(DateTime now,String tbName){
        String lastMonthStr = now.plusMonths(-1).toString(YEARMONTH_DATE_TIME_FORMATTER);
        String redisKey = RedisKey.DEL_BOOK_INFO_LOCK_PREFIX +lastMonthStr;

        Boolean hasSuc = customRedisTemplate.opsForValue().setIfAbsent(redisKey,String.valueOf(DateTime.now().getMillis()));
        if(hasSuc){//设置1天后过期
            customRedisTemplate.expire(redisKey,1, TimeUnit.DAYS);
        }else{
            log.info("[预定信息迁移]乐观锁获取失败，该线程不执行任务。");
            return Boolean.FALSE;
        }
        createTbIfNotExists(tbName);
        //逐页查出数据
        Integer curPageNo = 1;
        List<VehicleBookInfo> vehicleBookInfoList = null;
        do {
            Map<String, Object> params = Maps.newHashMap();
            params.put("yearMonth", lastMonthStr);
            params.put("pageStart", (curPageNo - 1) * COPY_BATCH_SIZE);
            params.put("pageSize", COPY_BATCH_SIZE);
            vehicleBookInfoList = mapper.getByPage4YearMonth(params);
            if(CollectionUtils.isNotEmpty(vehicleBookInfoList)){
                //插入数据到历史表
                for(VehicleBookInfo vehicleBookInfo : vehicleBookInfoList){
                    Map<String, Object> insertHisParams = Maps.newHashMap();
                    insertHisParams.put("tbName", tbName);
                    insertHisParams.put("id", vehicleBookInfo.getId());
                    insertHisParams.put("vehicle", vehicleBookInfo.getVehicle());
                    insertHisParams.put("yearMonth", vehicleBookInfo.getYearMonth());
                    insertHisParams.put("bookedDate", vehicleBookInfo.getBookedDate());
                    mapper.insertHis(insertHisParams);
                }
            }
            curPageNo++;
            log.info("【复制上月预定信息至历史表中】，当前复制页【"+curPageNo+"】，页大小【"+COPY_BATCH_SIZE+"】");
        }while(CollectionUtils.isNotEmpty(vehicleBookInfoList));
        log.info("复制上月预定信息至历史表中完成，总页数【"+(curPageNo-1)+"】");
;       return Boolean.TRUE;
    }

    /**
     * 删除上上月数据
     */
    @Transactional
    public void delDataTheMonthBeforeLast(DateTime now,String tbName){
        String theMonthBeforeLastStr = now.plusMonths(-2).toString(YEARMONTH_DATE_TIME_FORMATTER);
        Integer effected = 0;
        Integer total = 0;
        Map<String, Object> params = Maps.newHashMap();
        params.put("yearMonth", theMonthBeforeLastStr);
        params.put("batchSize", DEL_BATCH_SIZE);
        do {
            effected = mapper.del4YearMoth(params);
            total+=effected;
            log.info("开始删除预定信息数据，删除总数【"+total+"】");
        }while(effected!=0);
        log.info("删除预定信息数据完成");
    }


    private String getTbNameNow(){
        return TB_NAME_PREFIX+ DateTime.now().toString(YEAR_DATE_TIME_FORMATTER);
    }

    /**
     * 创建当年相关表格
     */
    private void createTbIfNotExists(String tbName){
        mapper.createTbIfNotExists(tbName);
    }

}
