package com.sptg.ad.biz.quartz;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.sptg.ad.api.entity.*;
import com.sptg.ad.api.stream.AdvertTaskCallbackProduceInterface;
import com.sptg.ad.biz.service.*;
import com.sptg.common.core.beans.PageBean;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.common.core.entity.PublishTask;
import com.sptg.common.core.entity.PublishTaskResult;
import com.sptg.common.core.enums.Instruct;
import com.sptg.device.api.entity.Device;
import com.sptg.device.api.feigns.DeviceFeign;
import com.sptg.device.api.feigns.MsgPublishFeign;
import com.sptg.permissions.api.dto.RegionAuthorizeDto;
import com.sptg.permissions.api.entity.RegionAuthorize;
import com.sptg.permissions.api.feigns.RegionAuthorizeFeign;
import com.sptg.statistics.api.dto.StatisticsAdPushCountDto;
import com.sptg.statistics.api.entity.StatisticsAdPushCount;
import com.sptg.statistics.api.feigns.StatisticsAdPushCountFeign;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * description: 广告定时任务
 */
@Slf4j
@Component
@AllArgsConstructor
public class AdvertQuartzTask {

    private final AdPushTaskDetailsServiceInterface adPushTaskDetailsServiceInterface;
    private final AdPushTaskServiceInterface adPushTaskServiceInterface;
    private final AdPushContentServiceInterface adPushContentServiceInterface;
    private final AdPushContentImgServiceInterface adPushContentImgServiceInterface;
    private final MsgPublishFeign msgPublishFeign;
    private final DeviceFeign deviceFeign;
    private final RegionAuthorizeFeign regionAuthorizeFeign;
    private final RedisTemplate<String,String> redisTemplate;
    private final StatisticsAdPushCountFeign statisticsAdPushCountFeign;
    private final ThresholdConfigService thresholdConfigService;
    private final DeviceAdvertStatisticsService deviceAdvertStatisticsService;
    private final AdvertTaskCallbackProduceInterface advertTaskCallbackProduceInterface;

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

    @Scheduled(cron = "0/30 * * * * *")
    public void run(){
        ValueOperations<String, String> operations = this.redisTemplate.opsForValue();
        String value = operations.get(REDIS_KEY);
        //  值存在,则结束定时器
        if (StringUtils.hasText(value)){
            return;
        }else {
            operations.set(REDIS_KEY,"advert quartz running");
        }
        Wrapper<AdPushTask> wrapper = new EntityWrapper<>();
        //发布状态{ -1：发布失败，0：待发布，1：发布成功，2：已撤销 }
        wrapper.eq("i_push_status",0);
        //当天凌晨2:00需要发布的任务
        wrapper.le("t_estimate_push_date",new Date());
        //查询满足条件需要发布的任务
        List<AdPushTask> list = this.adPushTaskServiceInterface.selectList(wrapper);

        list.forEach(task -> {
            try {
                //任务体
                List<AdPushContent> contentList = this.adPushContentServiceInterface.getAdPushContents(task.getId());
                contentList.forEach(content -> {
                    //获取广告图片
                    List<AdPushContentImg> imgList = adPushContentImgServiceInterface.getAdPushContentImgs(content.getId());
                    content.setAdPushContentImgs(imgList);
                });
                task.setAdPushContents(contentList);
                // 详情
                List<AdPushTaskDetails> taskDetails = this.adPushTaskDetailsServiceInterface.getAdPushTaskDetails(task.getId());
                // 获取关联外键Id列表
                List<Long> fkIdList = taskDetails.stream().map(AdPushTaskDetails::getFkId).collect(Collectors.toList());
                List<Long> deviceIdList = new ArrayList<>();
                switch (task.getPushType()) {
                    //  小区发布
                    case 1:
                        this.getDeviceIdByXqs(deviceIdList,fkIdList);
                        break;
                    //  单元发布
                    case 2:
                        this.getDeviceIdByUnits(deviceIdList,fkIdList);
                        break;
                    //  设备发布
                    case 3:
                        deviceIdList.addAll(fkIdList);
                        break;
                    //  区域发布
                    case 4:
                        this.getDeviceIdByRegions(deviceIdList,fkIdList,task.getOrgPosition());
                        break;
                    default:
                        break;
                }
                //  更新任务状态
                task.setPushStatus(OperationConstant.ONE);
                task.setPushCount((long) deviceIdList.size());
                //  阈值校验
                this.fazhiCheck(task,deviceIdList);

                if (deviceIdList.size() > 0) {
                    //  判断是人脸广告还是闲时广告
                    Instruct instruct = task.getTaskType() == 1 ? Instruct.add_face_advert_task : Instruct.add_leisure_advert_task;
                    //  构建任务体,并发布
                    PublishTask publishTask = new PublishTask(task.getId(), instruct, task, deviceIdList);
                    //  任务类型：{ 1：广告，2：策略，3：公告 }
                    publishTask.setTaskType(1);
                    publishTask.setOrgId(task.getRootOrgId());
                    Map<String,String> map = new HashMap<>();
                    this.msgPublishFeign.publishTask(publishTask,map);
                }
                StatisticsAdPushCountDto statisticsAdPushCountDto=new StatisticsAdPushCountDto();
                statisticsAdPushCountDto.setAdPushTaskId(task.getId());
                //查询是否已经添加记录
                StatisticsAdPushCount statisticsAdPushCount = this.statisticsAdPushCountFeign.getStatisticsAdPushCountByTaskId(statisticsAdPushCountDto);
                if(statisticsAdPushCount==null){
                    statisticsAdPushCountDto.setCount(task.getContentCount());
                    //推送状态
                    statisticsAdPushCountDto.setPushState(OperationConstant.ZERO);
                    statisticsAdPushCountDto.setCreateDate(new Date());
                    statisticsAdPushCountDto.setRootOrgId(task.getRootOrgId());
                    statisticsAdPushCountDto.setOrgPosition(task.getOrgPosition());
                    this.statisticsAdPushCountFeign.addAdPushCount(statisticsAdPushCountDto);
                }
            }catch (Exception e){
                log.error(e.getMessage(),e);
            }finally {
                this.adPushTaskServiceInterface.updateAdPushTask(task);
            }
        });
        //  定时器运行完后删除Key
        this.redisTemplate.delete(REDIS_KEY);
    }

    private void fazhiCheck(AdPushTask task,List<Long> deviceIdList){
        //  判断是否启用阈值配置
        boolean isEnableFaZhi = null == task.getEnableThreshold() || 1 == task.getEnableThreshold();
        //  校验阈值
        if (isEnableFaZhi){
            List<Device> deviceList = this.deviceFeign.getListByIds(deviceIdList);
            Map<String, List<Device>> map = deviceList.stream().collect(Collectors.groupingBy(Device::getRegionCity));
            map.forEach((city,values) -> {
                //   获取市阈值
                ThresholdConfig config = this.thresholdConfigService.selectByRegionCode(task.getRootOrgId(), task.getTaskType(), city);
                if (null == config){
                    //  获取省阈值
                    config = this.thresholdConfigService.selectByRegionCode(task.getRootOrgId(), task.getTaskType(), values.get(0).getRegionProvince());
                }
                if (null != config){
                    for (Device device : values){
                        //  获取设备的广告数量
                        DeviceAdvertStatistics statistics = this.deviceAdvertStatisticsService.selectCurrentMonthAdvertStatistics(device.getId(), task.getTaskType());
                        if (statistics.getAdCount() > config.getValue()){
                            PublishTaskResult taskResult = new PublishTaskResult();
                            taskResult.setTaskId(task.getId());
                            taskResult.setDeviceId(device.getId());
                            taskResult.setDeviceName(device.getName());
                            taskResult.setSerialNumber(device.getSerialNumber());
                            taskResult.setInstallPath(device.getInstallPath());
                            taskResult.setXqName(device.getXqName());
                            taskResult.setDyName(device.getDyName());
                            taskResult.setPushStatus(2);
                            taskResult.setRemark("超出阈值");
                            this.advertTaskCallbackProduceInterface.output().send(MessageBuilder.withPayload(taskResult).build());
                            //  移除超过阈值的设备
                            deviceIdList.remove(device.getId());
                        }
                    }
                }
            });
        }
    }

    private void getDeviceIdByRegions(List<Long> deviceIdList,List<Long> fkIdList,String position){
        PageBean<RegionAuthorize, RegionAuthorizeDto> pageBean = new PageBean<>(1,100);
        RegionAuthorizeDto dto = new RegionAuthorizeDto();
        dto.setUserOrgPosition(position);
        dto.setAreaIdList(fkIdList);
        pageBean.setDto(dto);
        List<Long> xqIdList = new ArrayList<>();
        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()));
        }
        this.getDeviceIdByXqs(deviceIdList,xqIdList);
    }

    private void getDeviceIdByXqs(List<Long> deviceIdList,List<Long> fkIdList){
        fkIdList.forEach(xqId -> {
            List<Device> deviceList = this.deviceFeign.getListByXqId(xqId);
            deviceList.forEach(device -> deviceIdList.add(device.getId()));
        });
    }

    private void getDeviceIdByUnits(List<Long> deviceIdList,List<Long> fkIdList){
        List<Device> deviceList = this.deviceFeign.getListByUnitIds(fkIdList);
        deviceList.forEach(device -> deviceIdList.add(device.getId()));
    }

}
