package com.friday.custody.quartz;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.friday.custody.service.basicService.AccoBalanceChangeRecordService;
import com.friday.custody.service.basicService.NotifierInfoService;
import com.friday.custody.service.basicService.QuartzScheduleTaskService;
import com.friday.custody.service.trustService.htsc.common.HtscConstants;
import com.friday.custody.dto.MsgSendDto;
import com.friday.custody.entity.AccoBalanceChangeRecordEntity;
import com.friday.custody.entity.NotifierInfoEntity;
import com.friday.custody.entity.ScheduleTask;
import com.friday.custody.entity.SubscribeFundInfoEntity;
import com.friday.custody.utils.JsonUtils;
import com.friday.custody.utils.MailSendUtil;
import com.friday.base.common.response.DubboResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.friday.custody.common.CustodyContants.*;

/**
 * 余额变动提醒-合并消息后，定时发送
 * TAIE-17480
 */
@DisallowConcurrentExecution
@Slf4j
public class MergedMessageNoticeByUserConfigJob extends QuartzJobBean {
    @Autowired
    private NotifierInfoService notifierInfoService;
    @Autowired
    private AccoBalanceChangeRecordService balanceChangeRecordService;
    @Autowired
    private QuartzScheduleTaskService scheduleTaskService;
    @Autowired
    MailSendUtil mailSendUtil;

    private static final int retryTimes = 2;

    private static final String mailSubject = "【华小生】【募集户/托管户余额变动】";

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getTrigger().getJobDataMap();
        int notifierId = jobDataMap.getInt("notifierId");
        String endTime = jobDataMap.getString("notifyTime");
        NotifierInfoEntity notifierInfo = notifierInfoService.getById(notifierId);
        List<SubscribeFundInfoEntity> fundInfoList = notifierInfoService.getFundInfoListBySubscribeId(notifierId);
        List<String> fundCodeList = fundInfoList.stream().map(t -> t.getSubscribeFundCode()).collect(Collectors.toList());
        List<String> timeList = getTimeListByNotifyId(notifierId);
        LocalDateTime startTime = getStartTime(timeList, endTime);
        LocalDateTime localDateEndTime = getEndTime(endTime);

        List<AccoBalanceChangeRecordEntity> balanceChangeList = getBalanceChangeList(fundCodeList, startTime, localDateEndTime);
        String content = null;
        List<String> smsList = null;
        if (!CollectionUtils.isEmpty(balanceChangeList)) {
            content = generateBalanceChangeContent(balanceChangeList);
            smsList = generateBalanceChangeContentForSms(balanceChangeList);
        }
        //send sms
        if (!ObjectUtils.isEmpty(notifierInfo.getNoticeMethod())
                && (notifierInfo.getNoticeMethod() == NOTICE_MENTHODS_ALL || notifierInfo.getNoticeMethod() == NOTICE_MENTHODS_SMS) && CollectionUtils.isNotEmpty(smsList)) {
            for (String smsContent : smsList) {
                sendSms(notifierInfo.getMobileNo(),smsContent);
                log.info("余额变动短信定时提醒：{}，{}", notifierInfo.getMobileNo(), smsContent);
            }
        }
        //send mail
        if (!ObjectUtils.isEmpty(notifierInfo.getNoticeMethod())
                && (notifierInfo.getNoticeMethod() == NOTICE_MENTHODS_ALL || notifierInfo.getNoticeMethod() == NOTICE_MENTHODS_MAIL)
                && content != null) {
            String emailDelimiterContent = content.replaceAll("\r\n", "<br>");
            String mailContent = emailDelimiterContent + "<br>更多信息，可前往华小生（" + "<a href=\"https://huatech.htsc.com.cn/helson/home\" target=\"_blank\">" +
                    "https://huatech.htsc.com.cn/helson/home</a>" + "）-私募管理平台查看详情。";
            sendMail(notifierInfo.getEmailAddress(), mailSubject, mailContent);
            log.info("余额变动邮件定时提醒：{}，{}", notifierInfo.getEmailAddress(), mailContent);
        }
    }

    private LocalDateTime getEndTime(String endTime) {
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
        LocalTime localTime = LocalTime.parse(endTime, timeFormatter);
        LocalDate localDate = LocalDate.now();
        return LocalDateTime.of(localDate, localTime);
    }

    /**
     * 根据订阅人表主键 查询用户设置的时间点
     * 时间点格式：HH:mm
     *
     * @return
     */
    private List<String> getTimeListByNotifyId(Integer notifyId) {
        List<String> result = new ArrayList<>();
        List<ScheduleTask> list = scheduleTaskService.list();
        for (ScheduleTask scheduleTask : list) {
            if (null != scheduleTask.getParameters()) {
                Map<String, Object> parameterMap = JsonUtils.X.parse(scheduleTask.getParameters(),
                        new TypeReference<Map<String, Object>>() {
                        });
                if (parameterMap.get("notifierId").equals(notifyId)) {
                    result.add(parameterMap.get("notifyTime").toString());
                }
            }

        }
        return result;
    }

    private LocalDateTime getStartTime(List<String> timeList, String endTime) {
        String startTime = null;
        Boolean startFromYesterday = false;
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
        LocalTime endLocalTime = LocalTime.parse(endTime, timeFormatter);

        PriorityQueue<LocalTime> localTimes = new PriorityQueue<>(Comparator.reverseOrder());
        for (String timeStr : timeList) {
            LocalTime localTime = LocalTime.parse(timeStr, timeFormatter);
            localTimes.add(localTime);
        }
        Iterator<LocalTime> iterator = localTimes.iterator();

        while (iterator.hasNext()) {
            LocalTime nextTime = iterator.next();
            if (nextTime.isBefore(endLocalTime)) {
                startTime = nextTime.toString();
                break;
            }
        }
        if (startTime == null) {
            startTime = localTimes.peek().toString();
            startFromYesterday = true;
        }
        LocalTime startLocalTime = LocalTime.parse(startTime, timeFormatter);
        LocalDate localDate = startFromYesterday ? LocalDate.now().minusDays(1) : LocalDate.now();

        return LocalDateTime.of(localDate, startLocalTime);
    }

    private List<AccoBalanceChangeRecordEntity> getBalanceChangeList(List<String> fundCodeList, LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<AccoBalanceChangeRecordEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .in(AccoBalanceChangeRecordEntity::getFundCode, fundCodeList)
                .between(AccoBalanceChangeRecordEntity::getUpdateTime, startTime, endTime)
                .orderByDesc(AccoBalanceChangeRecordEntity::getUpdateTime);
        return balanceChangeRecordService.list(queryWrapper);
    }

    private boolean sendSms(String mobileNo, String smsContent) {
//        if (StringUtils.isNotBlank(mobileNo)) {
//            String[] mobileNoArr = mobileNo.trim().split(";");
//            List<String> mobileNoList = Arrays.asList(mobileNoArr);
//            // 短信通知
//            SmsMsgDto smsMsgDto = new SmsMsgDto();
//            List<SmsUserPojo> smsUserPojoList = new ArrayList<>();
//            for (String phone : mobileNoList) {
//                smsUserPojoList.add(new SmsUserPojo(phone, "ZZ323472"));
//            }
//            smsMsgDto.setMsg(smsContent);
//            smsMsgDto.setActualWorker("华小生");
//            smsMsgDto.setSmsUsers(smsUserPojoList);
//            smsMsgDto.setWeight(SmsWeightEnum.MID);
//            smsMsgDto.setSendTime(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
//            try {
//                for (int i = 0; i < retryTimes; i++) {
//                    DubboResult smsResult = notifyService.doNotify(smsMsgDto);
//                    if (!smsResult.success()) {
//                        log.error("短信发送失败:收件人为{},短信内容为{}", mobileNo, smsContent);
//                        continue;
//                    }
//                    return smsResult.success();
//                }
//            } catch (Exception e) {
//                log.error("募集户,托管户变动提醒发送短信失败！", e);
//            }
//        }
        return true;
    }

    private String generateBalanceChangeContent(List<AccoBalanceChangeRecordEntity> list) {

        StringJoiner mjInflow = new StringJoiner(System.lineSeparator());
        StringJoiner mjOutflow = new StringJoiner(System.lineSeparator());
        StringJoiner tgInflow = new StringJoiner(System.lineSeparator());
        StringJoiner tgOutflow = new StringJoiner(System.lineSeparator());

        StringJoiner resultStringJoiner = new StringJoiner(System.lineSeparator());

        for (AccoBalanceChangeRecordEntity record : list) {
            BigDecimal delta = record.getAccoBalanceAfter().subtract(record.getAccoBalanceBefore()).setScale(2);
            if (delta.compareTo(BigDecimal.ZERO) > 0 && HtscConstants.MJ_ACCOUNT_TYPE_CODE.equals(record.getAccoTypeCode())) {
                String content = record.getFundName() + "入账" + delta.abs() + "元";
                mjInflow.add(content);
            }
            if (delta.compareTo(BigDecimal.ZERO) < 0 && HtscConstants.MJ_ACCOUNT_TYPE_CODE.equals(record.getAccoTypeCode())) {
                String content = record.getFundName() + "出账" + delta.abs() + "元";
                mjOutflow.add(content);
            }
            if (delta.compareTo(BigDecimal.ZERO) > 0 && HtscConstants.TG_ACCOUNT_TYPE_CODE.equals(record.getAccoTypeCode())) {
                String content = record.getFundName() + "入账" + delta.abs() + "元";
                tgInflow.add(content);
            }
            if (delta.compareTo(BigDecimal.ZERO) < 0 && HtscConstants.TG_ACCOUNT_TYPE_CODE.equals(record.getAccoTypeCode())) {
                String content = record.getFundName() + "出账" + delta.abs() + "元";
                tgOutflow.add(content);
            }

        }
        if (mjInflow.length() != 0) {
            resultStringJoiner.add("【华小生】【募集户余额变动】【入账】");
            resultStringJoiner.merge(mjInflow);

        }
        if (mjOutflow.length() != 0) {
            resultStringJoiner.add("【华小生】【募集户余额变动】【出账】");
            resultStringJoiner.merge(mjOutflow);

        }
        if (tgInflow.length() != 0) {
            resultStringJoiner.add("【华小生】【托管户余额变动】【入账】");
            resultStringJoiner.merge(tgInflow);

        }
        if (tgOutflow.length() != 0) {
            resultStringJoiner.add("【华小生】【托管户余额变动】【出账】");
            resultStringJoiner.merge(tgOutflow);

        }
        return resultStringJoiner.toString();
    }

    private List<String> generateBalanceChangeContentForSms(List<AccoBalanceChangeRecordEntity> list) {
        List<String> result = new ArrayList<>();

        StringBuilder mjInflow = new StringBuilder();
        StringBuilder mjOutflow =new StringBuilder();
        StringBuilder  tgInflow = new StringBuilder();
        StringBuilder tgOutflow = new StringBuilder();

        for (AccoBalanceChangeRecordEntity record : list) {
            BigDecimal delta = record.getAccoBalanceAfter().subtract(record.getAccoBalanceBefore()).setScale(2);
            if (delta.compareTo(BigDecimal.ZERO) > 0 && HtscConstants.MJ_ACCOUNT_TYPE_CODE.equals(record.getAccoTypeCode())) {
                String content = record.getFundName() + "入账" + delta.abs() + "元;";
                mjInflow.append(content);
            }
            if (delta.compareTo(BigDecimal.ZERO) < 0 && HtscConstants.MJ_ACCOUNT_TYPE_CODE.equals(record.getAccoTypeCode())) {
                String content = record.getFundName() + "出账" + delta.abs() + "元;";
                mjOutflow.append(content);
            }
            if (delta.compareTo(BigDecimal.ZERO) > 0 && HtscConstants.TG_ACCOUNT_TYPE_CODE.equals(record.getAccoTypeCode())) {
                String content = record.getFundName() + "入账" + delta.abs() + "元;";
                tgInflow.append(content);
            }
            if (delta.compareTo(BigDecimal.ZERO) < 0 && HtscConstants.TG_ACCOUNT_TYPE_CODE.equals(record.getAccoTypeCode())) {
                String content = record.getFundName() + "出账" + delta.abs() + "元;";
                tgOutflow.append(content);
            }

        }
        if (mjInflow.length() != 0) {
            String smsCotent = "【华小生】【募集户余额变动】【入账】"
                    .concat(mjInflow.toString())
                            .concat("可前往华小生-私募管理平台中查看详情。");
            result.add(smsCotent);

        }
        if (mjOutflow.length() != 0) {
            String smsCotent = "【华小生】【募集户余额变动】【出账】"
                    .concat(mjOutflow.toString())
                    .concat("可前往华小生-私募管理平台中查看详情。");
            result.add(smsCotent);

        }
        if (tgInflow.length() != 0) {
            String smsCotent = "【华小生】【托管户余额变动】【入账】"
                    .concat(tgInflow.toString())
                    .concat("可前往华小生-私募管理平台中查看详情。");
            result.add(smsCotent);

        }
        if (tgOutflow.length() != 0) {
            String smsCotent = "【华小生】【托管户余额变动】【出账】"
                    .concat(tgOutflow.toString())
                    .concat("可前往华小生-私募管理平台中查看详情。");
            result.add(smsCotent);
        }
        return result;
    }


    private boolean sendMail(String mailAddress, String subject, String mailContent) {
        if (StringUtils.isNotBlank(mailAddress)) {
            String[] mailArr = mailAddress.trim().split(";");
            MsgSendDto msgSendDto = MsgSendDto.builder()
                    .subject(subject) //邮件主题
                    .content(mailContent) //邮件内容
                    .emailList(Arrays.asList(mailArr))//接收人邮箱地址
                    .build();
            try {
                for (int i = 0; i < retryTimes; i++) {
                    Boolean isSendMail = mailSendUtil.sendMail(msgSendDto);
                    if (!isSendMail) {
                        log.error("发送邮件失败:收件人为{},邮件主题为{},邮件内容为{}", mailAddress, subject, mailContent);
                        continue;
                    }
                    return true;
                }
            } catch (Exception e) {
                log.error("募集户,托管户变动提醒发送邮件失败！", e);
            }
        }
        return false;
    }
}
