package net.northking.cctp.device.schedule;

import net.northking.cctp.common.http.ResultWrapper;
import net.northking.cctp.device.api.activity.service.DeviceActivityApiService;
import net.northking.cctp.device.bus.feign.PlatformFeign;
import net.northking.cctp.device.bus.feign.dto.UserInfoDto;
import net.northking.cctp.device.bus.publisher.DeviceStatusPublisher;
import net.northking.cctp.device.config.EmailConfig;
import net.northking.cctp.device.constants.DeviceConstants;
import net.northking.cctp.device.db.entity.*;
import net.northking.cctp.device.db.service.*;
import net.northking.cctp.device.util.DeviceStatusUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.mail.MailSendException;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.locks.Lock;

@Component
@RefreshScope
public class DeviceSchedule {

    private final static Logger logger = LoggerFactory.getLogger(DeviceSchedule.class);

    @Autowired
    private RedisLockRegistry lockRegistry;

    @Autowired
    private CdDeviceTenantService cdDeviceTenantService;

    @Autowired
    private CdDeviceProjectService cdDeviceProjectService;

    @Autowired
    private CdDeviceStatusService cdDeviceStatusService;

    @Autowired
    private CdMobileDeviceService cdMobileDeviceService;

    @Autowired
    private CdPcDeviceService cdPcDeviceService;

    @Autowired
    private CdDeviceModelService cdDeviceModelService;

    @Autowired
    private CdDeviceTokenService cdDeviceTokenService;

    @Autowired
    private CdEngineInfoService cdEngineInfoService;

    @Autowired
    private JavaMailSenderImpl javamailsender;

    @Value("${spring.mail.username}")
    private String userName;

    @Autowired
    private PlatformFeign platformFeign;

    @Autowired
    private DeviceStatusPublisher deviceStatusPublisher;

    @Autowired
    private DeviceStatusUtil statusUtil;

    @Autowired
    private CdDeviceCtrlService cdDeviceCtrlService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private EmailConfig emailConfig;

    @Autowired
    private DeviceActivityApiService activityApiService;

    @Scheduled(cron = "0 5 0 * * *")
    public void recycleDevice() {
        Lock lock = lockRegistry.obtain("scheduler:DeviceSchedule.recycleDevice");
        try {
            if (!lock.tryLock()) {
                return;
            } else {
                logger.info("------------------回收设备开始------------------");
                //查询出租户过期的设备
                List<String> ids = this.cdDeviceTenantService.queryExpiredDevice();
                if (ids.size() > 0) {
                    //回收分配到系统的设备
                    List<Object> list = new ArrayList<>(ids);
                    this.cdDeviceProjectService.deleteByPrimaryKeys(list);
                }
                //回收自动过期设备
                Integer recycleNum = this.cdDeviceTenantService.recycleDevice();
                Integer recycleNum1 = this.cdDeviceProjectService.recycleDevice();

                logger.info("-----------------回收设备数:{}--------------", recycleNum + recycleNum1);
            }
        }catch (Exception e){
            logger.error("定时回收设备异常:",e);
        }finally {
            lock.unlock();
        }
    }


    @Scheduled(cron = "0 0/1 * * * *")
    @Transactional
    public void offlineSendEmail() {
        logger.info("---------------------------校验设备与引擎过期定时任务：开始-----------------------------------");
        //查询离线5分钟的设备
        List<CdDeviceStatus> deviceList = this.cdDeviceStatusService.findOfflineDevice();
        for (CdDeviceStatus deviceStatus : deviceList) {
            if (deviceStatus.getDeviceType().equals("1")) {
                Lock lock = lockRegistry.obtain("mobile:device:" + deviceStatus.getId());
                try {
                    if (lock.tryLock()) {
                        //释放设备
                        this.cdDeviceTokenService.deleteByPrimaryKey(deviceStatus.getId());
                        //离线设备
                        deviceStatus.setUsageStatus("1");
                        deviceStatus.setDeviceStatus("2");
                        this.cdDeviceStatusService.updateByPrimaryKey(deviceStatus);//1
                        logger.info("-----------------------------------------【{}-{}】设备已离线，超过5分钟，已发送邮件----------------------------------------", deviceStatus.getId(), deviceStatus.getDeviceType());
                        deviceStatusPublisher.sendDeviceStateFanoutMQ(deviceStatus.getId());
                        if (emailConfig.isStatus()){//开发环境：false 测试环境：true
                            sendEmail(deviceStatus);
                        }
                    }
                } catch (Exception e) {
                    logger.error("更新设备状态发生异常：", e);
                } finally {
                    lock.unlock();
                }
            } else if (deviceStatus.getDeviceType().equals("2")) {
                Lock lock = lockRegistry.obtain("pc:device:" + deviceStatus.getId());
                try {
                    if (lock.tryLock()) {
                        //释放设备
                        this.cdDeviceTokenService.deleteByPrimaryKey(deviceStatus.getId());
                        //离线设备
                        deviceStatus.setUsageStatus("3");
                        deviceStatus.setDeviceStatus("2");
                        this.cdDeviceStatusService.updateByPrimaryKey(deviceStatus);//1
                        logger.info("-----------------------------------------【{}-{}】设备已离线，超过5分钟，已发送邮件----------------------------------------", deviceStatus.getId(), deviceStatus.getDeviceType());
                        deviceStatusPublisher.sendDeviceStateFanoutMQ(deviceStatus.getId());
                        if (emailConfig.isStatus()){//开发环境：false 测试环境：true
                            sendEmail(deviceStatus);
                        }
                    }
                } catch (Exception e) {
                    logger.error("更新设备状态发生异常：", e);
                } finally {
                    lock.unlock();
                }
            }
        }
        //查询离线5分钟的引擎
        List<CdEngineInfo> engineList = cdEngineInfoService.queryEngineOffLive();
        if (engineList.size() > 0) {
            List<String> ids = new ArrayList<>();
            for (CdEngineInfo engineInfo : engineList) {
                ids.add(engineInfo.getId());
                logger.info("引擎 【{}】已离线超过5分钟", engineInfo.getIpAddr());
                CdDeviceStatus status = new CdDeviceStatus();
                status.setId(engineInfo.getDeviceId());
                status.setUsageStatus("3");
                statusUtil.updatePcStatus(status);
            }
            this.cdEngineInfoService.updateEngineStatus(ids);
            try {
                logger.debug("释放引擎占用的设备");
                List<CdDeviceToken> deviceTokenList = this.cdDeviceTokenService.queryByEngineIds(ids);
                activityApiService.release(deviceTokenList);
                logger.debug("删除缓存中引擎线程的使用率");
                redisTemplate.opsForZSet().remove(DeviceConstants.ENGINE_MOB_ACTIVE_THREAD_KEY, ids.toArray());
            } catch (Exception e) {
                logger.error("释放引擎占用的设备失败", e);
            }
        }
        logger.info("---------------------------校验设备与引擎过期定时任务：结束-----------------------------------");

        List<String> list = this.cdDeviceCtrlService.queryCtrlOffLive();
        for (String ctrlId : list) {
            String lastHeart = (String) redisTemplate.opsForValue().get("UITEST-ctrl:heart:" + ctrlId);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                if (!StringUtils.isEmpty(lastHeart)) {
                    Date date = sdf.parse(lastHeart);
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(date);
                    calendar.add(Calendar.MINUTE, 5);
                    if (calendar.getTime().before(new Date())) {
                        //设置上位机离线
                        CdDeviceCtrl ctrl = new CdDeviceCtrl();
                        ctrl.setId(ctrlId);
                        ctrl.setCtrlStatus("0");
                        this.cdDeviceCtrlService.updateByPrimaryKey(ctrl);
                    }
                }
            } catch (ParseException e) {
                logger.error("", e);
            }
        }
    }


    public void sendEmail(CdDeviceStatus status) {
        try {
            String deviceName = new String();
            //拥有设备管理员角色的用户
            ResultWrapper<List<UserInfoDto>> wrapper = this.platformFeign.deviceManageUsers();
            List<UserInfoDto> dtoList = wrapper.getData();
            //查询设备名称
            if (dtoList != null && dtoList.size() > 0) {
                if (status.getDeviceType().equals("1")) {
                    CdMobileDevice mobileDevice = this.cdMobileDeviceService.findByPrimaryKey(status.getId());
                    CdDeviceModel model = this.cdDeviceModelService.findByPrimaryKey(mobileDevice.getModelId());
                    deviceName = model.getModelName();
                } else if (status.getDeviceType().equals("2")) {
                    CdPcDevice pcDevice = this.cdPcDeviceService.findByPrimaryKey(status.getId());
                    deviceName = pcDevice.getDeviceName();
                }
                MimeMessage mimeMessage = javamailsender.createMimeMessage();
                MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
                helper.setFrom(userName);
                helper.setSubject("设备离线通知");
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String time = format.format(new Date());
                helper.setText("【" + time + "】，【" + deviceName + "】状态为：离线，请前往检查！");
                int successCount = 0;
                String[] user = new String[dtoList.size()];
                int num = 0;
                for (UserInfoDto infoDto : dtoList) {
                    if (!infoDto.getMail().isEmpty()) {
                        user[num] = infoDto.getMail();
                        num++;
                    }
                }
                logger.info("Send Email -------------------------------------> start");
                helper.setTo(user);
                javamailsender.send(mimeMessage);
                logger.info("Send Email -------------------------------------> end");
            }
        } catch (MessagingException | MailSendException e) {
            logger.error("发送邮件发生异常：", e);
        }
    }


}
