package com.jpsoft.shinestar.scheduled;

import cn.hutool.core.date.DateUtil;
import com.jpsoft.shinestar.config.OSSConfig;
import com.jpsoft.shinestar.config.WxConfig;
import com.jpsoft.shinestar.modules.base.constant.AttendanceTypes;
import com.jpsoft.shinestar.modules.base.entity.*;
import com.jpsoft.shinestar.modules.base.service.*;
import com.jpsoft.shinestar.modules.business.entity.WorkAttendance;
import com.jpsoft.shinestar.modules.business.service.WorkAttendanceService;
import com.jpsoft.shinestar.modules.common.utils.JwtUtil;
import com.jpsoft.shinestar.modules.common.utils.WechatMessageUtil;
import com.jpsoft.shinestar.modules.sys.entity.SysLog;
import com.jpsoft.shinestar.modules.sys.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
@Slf4j
public class NoticeStatAsyncTask {
    @Value("${jwt.secret}")
    private String jwtSecret;

    @Autowired
    private AlarmConfigService alarmConfigService;

    @Autowired
    private WarningPusherService warningPusherService;

    @Autowired
    private PersonDeviceFilterLogService personDeviceFilterLogService;

    @Autowired
    private CompanyInfoService companyInfoService;

    @Autowired
    private CompanyPositionService companyPositionService;

    @Autowired
    private WorkAttendanceService workAttendanceService;

    @Autowired
    private PersonDeviceLogService personDeviceLogService;

    @Autowired
    private PersonInfoService personInfoService;

    @Autowired
    private PersonPopedomService personPopedomService;

    @Autowired
    private WxConfig wxConfig;

    @Autowired
    private OSSConfig ossConfig;

    @Value("${mobile.unMeasureUrl}")
    private String unMeasureUrl;

    @Value("${wx.notice.remindTmplCode}")
    private String remindTmplCode;

    @Value("${wx.notice.supervisionTmplCode}")
    private String supervisionTmplCode;

    @Autowired
    private HolidayInfoService holidayInfoService;

    @Autowired
    private SysLogService sysLogService;

    @Async
    public void noticeAndStat(DateTime now, AlarmConfig alarmConfig, DateTime startTime, DateTime attendanceTime, DateTime endTime, int status) {
        int weekday = now.getDayOfWeek();
        String date = now.toString("yyyy-MM-dd");

        CompanyInfo companyInfo = companyInfoService.get(alarmConfig.getCompanyId());

        //查询当前考勤关联单位
        List<CompanyInfo> relatedCompanyList = new ArrayList<>();

        if (alarmConfig.getSubordinate()!=null && alarmConfig.getSubordinate()) {
            relatedCompanyList = companyInfoService.findAllCompanyByCode(companyInfo.getCode() + "%");
        } else {
            relatedCompanyList.add(companyInfo);
        }

        //查询子单位是否有考勤设置，如果有要排除子单位
        List<String> excludeCompanyList = alarmConfigService.findSubCompanyList(companyInfo.getCode() + "%", companyInfo.getId());

        //针对每个单位、部门进行统计
        for (CompanyInfo relatedCompany : relatedCompanyList) {
            //下级单位单独设置了考勤
            if (excludeCompanyList.contains(relatedCompany.getId())) {
                continue;
            }

            //最近一周的节假日
            Set<String> holidaySet = holidayInfoService.getHolidaySetByDate(relatedCompany.getCode(), now.minusDays(7).toDate(), now.plusDays(1).toDate(), false);

            //虽然放假但正常上班
            Map<String, HolidayInfo> fakeHolidayMap = holidayInfoService.getHolidayMapByDate(relatedCompany.getCode(), now.minusDays(7).toDate(), now.plusDays(1).toDate(), true);

            if (holidaySet.contains(date) && !fakeHolidayMap.containsKey(date)) {
                return;
            }

            String weekdays = alarmConfig.getWeekdays();

            if (fakeHolidayMap.containsKey(date)) {
                //虽然放假但需要工作
                HolidayInfo holidayInfo = fakeHolidayMap.get(date);

                //参考工作日
                weekday = holidayInfo.getRefWeekday();
            }

            //开始时间
            if (weekdays.indexOf(String.valueOf(weekday)) != -1) {
                //todo 上下班打卡提醒
                if (status==1) {
                    writeDbLog(String.format("考勤测温提醒：考勤时间：%s,当前时间：%s",
                            attendanceTime.toString("yyyy-MM-dd HH:mm"),
                            now.toString("yyyy-MM-dd HH:mm")),
                            alarmConfig.getCompanyId());

                    //todo 通知个人
                    if (alarmConfig.getNeedMeasureTemperature()) {
                        noticePerson(relatedCompany.getId(), alarmConfig, startTime, endTime);
                    }
                }
                //todo 考勤时间已到
                else if (status==2) {
                    //todo  未测量人通知管理人员
                    if (alarmConfig.getClassifier().equals(1)) {
                        //上班
//                                if(alarmConfig.getNeedMeasureTemperature()) {
//                                    noticeManager(alarmConfig, startTime, attendanceTime);
//                                }
                    }
                }
                //todo 截止时间已到
                else if (status==3) {
                    if (alarmConfig.getClassifier().equals(2)) {
                        //下班
//                                if(alarmConfig.getNeedMeasureTemperature()) {
//                                    noticeManager(alarmConfig, attendanceTime, endTime);
//                                }
                    }

                    //未在开始截止时间内打卡算缺卡
                    workAttendanceService.recordUnAttendance(relatedCompany.getId(), alarmConfig, startTime.toDate(), attendanceTime.toDate(), endTime.toDate(), WorkAttendance.MISSING);
                }
            }
        }
    }

    public void noticePerson(String companyId, AlarmConfig alarmConfig, DateTime startTime, DateTime endTime) {
        CompanyInfo companyInfo = companyInfoService.get(companyId);

        //todo 查询该单位当前时间段是否有人员未设备打卡测温
        List<Long> unmeasuredList = personDeviceLogService.queryUnAttendanceListByCompanyId(companyId, startTime.toDate(), endTime.toDate());

        writeDbLog(String.format(
                "查询考勤时段：%s~%s，未考勤人员数量:%s",
                startTime.toString("yyyy-MM-dd HH:mm"),
                endTime.toString("yyyy-MM-dd HH:mm"),
                unmeasuredList.size()
        ), companyInfo.getId());

        if (unmeasuredList.size() == 0) {
            return;
        }

        //todo 未打卡测温人推送微信通知
        for (Long personId : unmeasuredList) {
            PersonInfo personInfo = personInfoService.get(personId);

            //todo 查询该用户是否需要考勤
            PersonPopedom personPopedom = personPopedomService.hasEnableAttendanceByCompanyId(personId, companyInfo.getId());

            if (personPopedom == null) {
                continue;
            } else {
                //todo 当前用户所在单位今日是否放假
                boolean existHoliday = holidayInfoService.existByDateAndCompanyId(
                        startTime.withTimeAtStartOfDay().toDate(),
                        personPopedom.getCompanyId());

                if (existHoliday) {
                    continue;
                }
            }

            //工作不需要打外勤
            if ("1".equals(personInfo.getWorkStatus())) {
                if (alarmConfig.getAttendanceType().equals(AttendanceTypes.OUT)) {
                    //工作不需要打外勤
                    continue;
                }
            }

            //外出、出差
            if ("2".equals(personInfo.getWorkStatus()) || "3".equals(personInfo.getWorkStatus())) {
                if (alarmConfig.getAttendanceType().equals(AttendanceTypes.IN)) {
                    //出差不需要打内勤
                    continue;
                } else {
                    //有打卡记录则不提醒
                    WorkAttendance workAttendance = workAttendanceService.findByPersonIdAndPeriod(personId, startTime.toDate(), alarmConfig.getId());

                    if (workAttendance != null) {
                        continue;
                    }
                }
            }

            if ("4".equals(personInfo.getWorkStatus())) {
                //休假不需要提醒
                continue;
            }

            if (personInfo.getWechatNoticeEnabled() != null
                    && personInfo.getWechatNoticeEnabled()
                    && StringUtils.isNotEmpty(personInfo.getOpenId())) {
                String message = "尊敬的" + personInfo.getName();

//                if (alarmConfig.getClassifier()!=null && alarmConfig.getClassifier().equals(1)){
//                    message += ",请在" + startTime.toString("HH:mm") + "至" + attendanceTime.toString("HH:mm") + "时间内在单位（校园）内任意打卡点打卡及测温!";
//                }
//                else{
//                    message += ",请在" + attendanceTime.toString("HH:mm") + "至" + endTime.toString("HH:mm") + "时间内在单位（校园）内任意打卡点打卡及测温!";
//                }
                message += ",请抓紧时间在单位内任意打卡点打卡和测温。如已外出，请在小鹏管家中进行外勤打卡。";

                JSONObject sendData = new JSONObject();

                JSONObject first = new JSONObject();
                first.put("value", "未打卡提醒");
                first.put("color", "#FF0000");

                JSONObject keyword1 = new JSONObject();
                keyword1.put("value", personInfo.getName());
                keyword1.put("color", "#173177");

                JSONObject keyword2 = new JSONObject();
                keyword2.put("value", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
                keyword2.put("color", "#173177");

                JSONObject keyword3 = new JSONObject();
                keyword3.put("value", "待打卡");
                keyword3.put("color", "#173177");

                JSONObject remark = new JSONObject();
                remark.put("value", message);
                remark.put("color", "#173177");

                sendData.put("first", first);
                sendData.put("keyword1", keyword1);
                sendData.put("keyword2", keyword2);
                sendData.put("keyword3", keyword3);
                sendData.put("remark", remark);

                writeDbLog(String.format("向未打卡人：%s,%s发送打卡提醒通知", personInfo.getName(), personInfo.getOpenId()), alarmConfig.getCompanyId());

                WechatMessageUtil.sendNativeTemplate(wxConfig.getAppId(), wxConfig.getAppSecret(), remindTmplCode, personInfo.getOpenId(), sendData, null);
            }
        }
    }

    public void noticeManager(AlarmConfig alarmConfig, DateTime startTime, DateTime endTime) {
        CompanyInfo companyInfo = companyInfoService.get(alarmConfig.getCompanyId());

        String companyCode = companyInfo.getCode();

        if (alarmConfig.getSubordinate() != null && alarmConfig.getSubordinate()) {
            companyCode += "%";
        }

        //查询子单位是否有考勤设置，如果有要排除子单位
        List<String> excludeCompanyList = alarmConfigService.findSubCompanyList(companyInfo.getCode() + "%", companyInfo.getId());

        //todo 查询该单位当前时间段是否有人员未测体温
        List<Long> unmeasuredList = personDeviceLogService.queryUnAttendanceList(companyCode, startTime.toDate(), endTime.toDate(), excludeCompanyList);

        if (unmeasuredList.size() == 0) {
            return;
        }

        int total = unmeasuredList.size();

        //todo 查询该单位的通知人
        List<WarningPusher> pusherList = warningPusherService.findByCompanyId(companyInfo.getId());

        //todo 给单位相关人员推送通知
        for (WarningPusher pusher : pusherList) {
            if (StringUtils.isNotEmpty(pusher.getOpenId())
                    && pusher.getMissingNoticeEnabled() != null && pusher.getMissingNoticeEnabled()) {
                String message = "尊敬的" + pusher.getName()
                        + "," + startTime.toString("yyyy-MM-dd") + "时段" + startTime.toString("HH:mm") + "至" + endTime.toString("HH:mm")
                        + ",有" + total + "人未测量体温，具体名单请点击下方【查看详情】查看";

                //todo 生成未测量人员名单
                PersonInfo personInfo = personInfoService.findByOpenId(pusher.getOpenId());
                long personId = 0;

                if (personInfo != null) {
                    personId = personInfo.getId();
                }

                try {
                    writeDbLog(String.format("查询单位：%s,测温统计信息接收人: %s,personId=%s,未测温人数：%s",
                            companyInfo.getName(), pusher.getName(), personId, total), companyInfo.getId());

                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

                    String token = JwtUtil.createToken(jwtSecret, String.valueOf(personId), sdf.parse("2030-01-01"));

                    String url = unMeasureUrl + "?token=" + URLEncoder.encode(token, "UTF-8");
                    url += "&companyId=" + alarmConfig.getCompanyId();
                    url += "&queryDate=" + startTime.toString("yyyy-MM-dd");
                    url += "&alarmConfigId=" + alarmConfig.getId();

                    JSONObject sendData = new JSONObject();

                    JSONObject first = new JSONObject();
                    first.put("value", "未测温提醒");
                    first.put("color", "#FF0000");

                    JSONObject keyword1 = new JSONObject();
                    keyword1.put("value", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
                    keyword1.put("color", "#173177");

                    JSONObject keyword2 = new JSONObject();
                    keyword2.put("value", companyInfo.getName());
                    keyword2.put("color", "#173177");

                    JSONObject keyword3 = new JSONObject();
                    keyword3.put("value", pusher.getName());
                    keyword3.put("color", "#173177");

                    JSONObject remark = new JSONObject();
                    remark.put("value", message);
                    remark.put("color", "#173177");

                    sendData.put("first", first);
                    sendData.put("keyword1", keyword1);
                    sendData.put("keyword2", keyword2);
                    sendData.put("keyword3", keyword3);
                    sendData.put("remark", remark);

                    WechatMessageUtil.sendTemplate(sendData, wxConfig.getAppId(), wxConfig.getAppSecret(), supervisionTmplCode, pusher.getOpenId(), url);
                } catch (Exception ex) {
                    log.error(ex.getMessage(), ex);
                }
            }
        }
    }

    private void writeDbLog(String remark, String companyId) {
        SysLog sysLog = new SysLog();
        sysLog.setPointcut("未测体温提醒");
        sysLog.setUrl(companyId);
        sysLog.setRemark(remark);
        sysLog.setCreateTime(new Date());
        sysLogService.insert(sysLog);
    }
}
