package com.sptg.device.biz.quartz;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.sptg.common.core.beans.PageBean;
import com.sptg.common.core.beans.ResultBean;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.common.core.entity.PublishTask;
import com.sptg.common.core.enums.Instruct;
import com.sptg.common.core.util.DateUtil;
import com.sptg.device.api.entity.*;
import com.sptg.device.api.feigns.InstructPublishLogDustbinFeign;
import com.sptg.device.api.feigns.InstructPublishLogFeign;
import com.sptg.device.biz.service.*;
import com.sptg.permissions.api.dto.RegionAuthorizeDto;
import com.sptg.permissions.api.entity.RegionAuthorize;
import com.sptg.permissions.api.feigns.RegionAuthorizeFeign;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * title: TimeStrategyQuartzTask
 * package: com.sptg.device.biz.quartz
 * description: 时间策略定时任务
 *
 *                
 *                
 */
@Slf4j
@Component
@RequiredArgsConstructor
@Profile({"prod"})
public class TimeStrategyQuartzTask {

    private final DeviceServiceInterface deviceServiceInterface;
    private final RegionAuthorizeFeign regionAuthorizeFeign;
    private final MsgPublishService msgPublishService;
    private final TimeStrategyPushTaskServiceInterface timeStrategyPushTaskServiceInterface;
    private final  TimeStrategyTaskDetailsServiceInterface timeStrategyTaskDetailsServiceInterface;
    private final TimeStrategyTaskConfServiceInterface timeStrategyTaskConfServiceInterface;
    private final RedisTemplate<String,String> redisTemplate;
    private final InstructPublishLogFeign instructPublishLogFeign;
    private final InstructPublishLogDustbinFeign instructPublishLogDustbinFeign;


    // @Scheduled(cron = "0 0 3 * * ?")     每天3点执行
    // @Scheduled(cron = "*/5 * * * * ?")   每隔5秒执行

    private final static String REDIS_KEY = "strategy.quartz";

    /**
     * 功能描述: 时间策略定时发布任务
     *                
     *                      
     */
    @Scheduled(cron = "*/59 * * * * ?")
    public void timingPushTask(){
        ValueOperations<String, String> operations = this.redisTemplate.opsForValue();
        String value = operations.get(REDIS_KEY);
        //  值存在,则结束定时器
        if (StringUtils.hasText(value)){
            return;
        }else {
            operations.set(REDIS_KEY,"strategy quartz running");
        }
        Page<TimeStrategyPushTask> page = new Page<>();
        int pageNo = 0;
        page.setSize(100);
        while (true) {
            page.setCurrent(++pageNo);
            //  分页获取任务
            page =this.timeStrategyPushTaskServiceInterface.selectOvertimeTask(page);
            if (page.getRecords().size() == 0){
                //  结束循环
                break;
            }
            //  推送任务
            page.getRecords().forEach(task -> {
                //  发布屏保
                try{
                    task.setPushStatus(OperationConstant.TWO);
                    //  获取时间策略参数列表
                    Wrapper<TimeStrategyTaskConf> wrapper=new EntityWrapper<>();
                    wrapper.eq("l_task_id",task.getId());
                    List<TimeStrategyTaskConf> timeStrategyTaskConfList = this.timeStrategyTaskConfServiceInterface.selectList(wrapper);
                    timeStrategyTaskConfList.forEach(conf -> {
                        SimpleDateFormat sdf = new SimpleDateFormat("HHmm");
                        String beginTimeStr = sdf.format(conf.getBeginTime());
                        String endTimeStr = sdf.format(conf.getEndTime());
                        conf.setBeginTimeStr(beginTimeStr);
                        conf.setEndTimeStr(endTimeStr);
                    });
                    task.setTimeStrategyTaskConfList(timeStrategyTaskConfList);
                    //  获取关联外键Id列表
                    List<Long> fkIdList = this.timeStrategyTaskDetailsServiceInterface.getFkIdListByTaskId(task.getId());
                    List<Long> deviceIdList;
                    switch (task.getPushType()) {
                        //  小区发布
                        case 1:
                            deviceIdList = this.getDeviceIdByXqs(fkIdList);
                            break;
                        //  单元发布
                        case 2:
                            deviceIdList = this.getDeviceIdByUnits(fkIdList);
                            break;
                        //  设备发布
                        case 3:
                            deviceIdList = fkIdList;
                            break;
                        //  区域发布
                        case 4:
                            deviceIdList = this.getDeviceIdByRegions(fkIdList,task.getOrgPosition());
                            break;
                        default:
                            deviceIdList = new ArrayList<>(0);
                            break;
                    }
                    //  更新任务状态
                    task.setPushStatus(OperationConstant.TWO);
                    task.setPushCount((long) deviceIdList.size());

                    //  构建任务体,并发布
                    PublishTask publishTask = new PublishTask(task.getId(), Instruct.add_strategy_task, task, deviceIdList);
                    //  任务类型：{ 1：广告，2：策略，3：公告 }
                    publishTask.setTaskType(2);
                    this.msgPublishService.publishTask(publishTask);

                    task.setPushTime(new Date());
                }catch (Exception e){
                    task.setPushStatus(OperationConstant.ZERO);
                    task.setRemark("网络异常");
                }
                //  保存发布内容
                this.timeStrategyPushTaskServiceInterface.updateById(task);
            });
        }

        //  定时器运行完后删除Key
        this.redisTemplate.delete(REDIS_KEY);
    }

    private List<Long> getDeviceIdByRegions(List<Long> fkIdList,String position){
        List<Long> xqIdList = new ArrayList<>();
        PageBean<RegionAuthorize, RegionAuthorizeDto> pageBean = new PageBean<>();
        pageBean.setSize(100);
        RegionAuthorizeDto dto = new RegionAuthorizeDto();
        dto.setUserOrgPosition(position);
        dto.setAreaIdList(fkIdList);
        pageBean.setDto(dto);
        int pageNo = 0;
        while (true){
            ++ pageNo;
            pageBean.setCurrent(pageNo);
            //  得到授权小区列表
            Page<RegionAuthorize> page = this.regionAuthorizeFeign.pagingQuery(pageBean);
            if (page.getRecords().size() == 0){
                break;
            }
            page.getRecords().forEach(authorize -> xqIdList.add(authorize.getXqId()));
        }
        return this.getDeviceIdByXqs(xqIdList);
    }

    private List<Long> getDeviceIdByXqs(List<Long> fkIdList){
        List<Long> deviceIdList = new ArrayList<>();
        fkIdList.forEach(xqId -> {
            List<Device> deviceList = this.deviceServiceInterface.selectListByXqId(xqId);
            deviceList.forEach(device -> deviceIdList.add(device.getId()));
        });
        return deviceIdList;
    }

    private List<Long> getDeviceIdByUnits(List<Long> fkIdList){
        List<Device> deviceList = this.deviceServiceInterface.selectListByUnitIds(fkIdList);
        return deviceList.stream().map(Device::getId).collect(Collectors.toList());
    }

//    @Scheduled(cron = "*/59 * * * * ?")
    //每个月15号晚上12点执行
    @Scheduled(cron = "0 0 0 15 * ?")
    public void timer(){
        //获取当前时间的三个月前的时间
        Date beforeDate = beforeThreeMonDate();
        InstructPublishLog instructPublishLog = new InstructPublishLog();
        instructPublishLog.setBeginDate(beforeDate);
        List<InstructPublishLog> instructPublishLogList = instructPublishLogFeign.getListPutBin(instructPublishLog);
        if (instructPublishLogList.size() > 0){
            List<InstructPublishLogDustbin> instructPublishLogDustbinList = new ArrayList<>();
            instructPublishLogList.forEach(instructPublishLog1 -> {
                InstructPublishLogDustbin instructPublishLogDustbin = new InstructPublishLogDustbin();
                instructPublishLogDustbin.setOrgPosition(instructPublishLog1.getOrgPosition());
                instructPublishLogDustbin.setSerialNumber(instructPublishLog1.getSerialNumber());
                instructPublishLogDustbin.setInstructCode(instructPublishLog1.getInstructCode());
                instructPublishLogDustbin.setExchangeName(instructPublishLog1.getExchangeName());
                instructPublishLogDustbin.setInstructDescribe(instructPublishLog1.getInstructDescribe());
                instructPublishLogDustbin.setPublishData(instructPublishLog1.getPublishData());
                instructPublishLogDustbin.setStatus(instructPublishLog1.getStatus());
                instructPublishLogDustbin.setCreateTime(instructPublishLog1.getCreateTime());
                instructPublishLogDustbin.setHandleStatus(instructPublishLog1.getHandleStatus());
                instructPublishLogDustbin.setErrorMsg(instructPublishLog1.getErrorMsg());
                instructPublishLogDustbin.setLastModifyTime(instructPublishLog1.getLastModifyTime());
                instructPublishLogDustbin.setLastResendTime(instructPublishLog1.getLastResendTime());
                instructPublishLogDustbinList.add(instructPublishLogDustbin);
            });
            ResultBean<Boolean> bean = instructPublishLogDustbinFeign.insertLogDustbinList(instructPublishLogDustbinList);
            if (bean.getData()){
                ResultBean<Boolean> resultBean = instructPublishLogFeign.deletePutBinList(instructPublishLogList);
            }else {
                return;
            }
        }else {
            return;
        }
    }


    /**
     * 获取三个月前的时间
     * @return
     */
    private Date beforeThreeMonDate(){
        Date nowDate = new Date();
        Date beforeDate = new Date();
        Calendar calendar = Calendar.getInstance(); //得到日历
        calendar.setTime(nowDate);//把当前时间赋给日历
        calendar.add(Calendar.MONTH, -1);  //设置为前3月
        beforeDate = calendar.getTime();   //得到前3月的时间
        return beforeDate;
    }
}
