package com.cyksj.service.mail.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
import com.cyksj.common.util.StringUtil;
import com.cyksj.mapper.EmailConfigMapper;
import com.cyksj.mapper.GoodsCoursewareFileMapper;
import com.cyksj.mapper.GroupsRelationMapper;
import com.cyksj.mapper.OrderDonMapper;
import com.cyksj.model.entity.*;
import com.cyksj.redis.RedisService;
import com.cyksj.service.mail.MailService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ThreadLocalRandom;

/*
 *项目名: netflix
 *文件名: MailServiceImpl
 *创建者: JavaZou
 *创建时间:2023/1/3 15:54
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MailServiceImpl implements MailService {
	@Value("${spring.mail.username}")
	private String from;

	private final JavaMailSender mailSender;

	private final RedisService redisService;

	private final GoodsCoursewareFileMapper coursewareFileMapper;

	private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();

	private final GroupsRelationMapper groupsRelationMapper;

	private final OrderDonMapper orderDonMapper;

	private final EmailConfigMapper emailConfigMapper;

	private static List<JavaMailSenderImpl> senders;

	private static String IMG_HTML = "<p><img src='%s' width=200></p>";

	/**
	 * 获取邮箱客户端
	 */
	//@PostConstruct
	public void init() throws Exception {
		List<EmailConfig> emailConfigs = emailConfigMapper.selectList(null);
		senders = new ArrayList<>(emailConfigs.size());
		emailConfigs.forEach(emailConfig->{
			//过滤163邮箱
			if (emailConfig.getType() == 1) {
				return;
			}
			JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
			javaMailSender.setHost(emailConfig.getHost());
			javaMailSender.setProtocol(emailConfig.getProtocol());
			javaMailSender.setUsername(emailConfig.getUsername());
			javaMailSender.setPassword(emailConfig.getPassword());
			javaMailSender.setDefaultEncoding(emailConfig.getDefaultEncoding());
			Properties properties = new Properties();
			properties.setProperty("mail.smtp.auth", "true");
			properties.setProperty("mail.smtp.port", emailConfig.getPort().toString());
			properties.setProperty("mail.smtp.starttls.enable", "true");
			properties.setProperty("mail.smtp.starttls.required", "true");
			properties.setProperty("mail.smtp.ssl.enable", "true");

			properties.setProperty("mail.smtp.socketFactory.port", "465");
			properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
			properties.setProperty("mail.smtp.socketFactory.fallback", "false");
			javaMailSender.setJavaMailProperties(properties);
			senders.add(javaMailSender);
		});
		log.info("初始化邮箱大小:{}", senders.size());
	}

	@Override
	public String sendLoginCodeEmailToPeople(Integer digit, String toAddress) {
		// 生成验证码
		String code = StringUtil.getRandomCodeStr(digit);
		if (sendLoginCodeEmailToPeople(code, toAddress)) {
			//删除之前的验证码缓存key
			String key = RedisService.key.EMAIL_CODE_KEY.getNameFormat(toAddress);
			redisService.del(key);
			//将验证码存入redis
			redisService.set(key, code, RedisService.key.EMAIL_CODE_KEY.getTimeout());
			return code;
		}
		return null;
	}

	@Override
	public Boolean sendLoginCodeEmailToPeople(String code, String toAddress) {
		String subject = "【崇宇信息】登录验证码";
		String content = String.format("尊敬的用户，您的验证码为%s，此验证码仅用于银河录像。【崇宇信息】", code);
		boolean flag = sendMail(toAddress, subject, content);
		return flag;
	}

	@Override
	public void sendEmailMsgToPeople(String people, String subject, String msg) {
		log.info("发送邮件至用户:{}开始", people);
		if (sendMail(people, subject, msg)) {
			log.info("发送成功");
			return;
		}
	}

	@Override
	public void sendCoursewareByGoodsId(Long goodsId, Long relationId, Long userId, String goodsTitle, String email) throws Exception {
		//获取当前目前下的课程文件
		MimeMessage msg = mailSender.createMimeMessage();
		MimeMessageHelper helper = new MimeMessageHelper(msg, true, "utf-8");
		List<GoodsCoursewareFile> coursewareFiles = coursewareFileMapper.selectList(Wrappers.lambdaQuery(GoodsCoursewareFile.class)
				.eq(GoodsCoursewareFile::getGoodsId, goodsId)
				.eq(GoodsCoursewareFile::getStatus, true));
		if (coursewareFiles.isEmpty()) {
			throw BusinessRuntimeException.getInstance("未配置对应课件,请联系客服..");
		}
		//标题
		StringBuilder subject = new StringBuilder();
		StringBuilder sb = new StringBuilder(IMG_HTML.length());
		coursewareFiles.forEach(file->{
			try {
				helper.addAttachment(MimeUtility.encodeText(file.getFileName(), "utf-8", "B"), new File(file.getPath()));
				if (StrUtil.isNotBlank(file.getImg())) {
					sb.append(String.format(IMG_HTML, file.getImg()));
					sb.append("<br/>");
				}
				if (subject.length() > 0) {
					subject.append(StrUtil.EMPTY);
				}
				subject.append(file.getSubject());
			} catch (Exception e) {
			}
		});
		if (sb.length() == 0) {
			sb.append(goodsTitle);
		}
		if (subject.length() == 0) {
			subject.append("银河录像局AI课程");
		}
		helper.setSubject(subject.toString());
		helper.setText(sb.toString(), true);
		helper.setTo(email);
		TASK_EXECUTOR.execute(() -> {
			try {
				JavaMailSenderImpl sender = getJavaEmailServer();
				helper.setFrom(sender.getUsername());
				log.info("使用邮箱:{},开始给用户userId:{},relationId:{} 发送课程:{}专属课件", sender.getUsername(), userId, relationId, goodsTitle);
				sendMsgIfFailRetry(sender, msg);
			} catch (Exception e) {
				log.info("发送课件失败,error:{}", StringUtil.getErrorText(e));
				groupsRelationMapper.update(null, Wrappers.lambdaUpdate(GroupsRelation.class)
						.set(GroupsRelation::getAccount, null)
						.eq(GroupsRelation::getId, relationId)
						.and(qr -> qr.isNotNull(GroupsRelation::getAccount).or().ne(GroupsRelation::getAccount, StrUtil.EMPTY)));

				orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class)
						.set(OrderDon::getStatus, OrderDon.Status.hasPayment)
						.eq(OrderDon::getRelationId, relationId)
						.eq(OrderDon::getUserId, userId)
						.eq(OrderDon::getStatus, OrderDon.Status.complete));
			}
		});
	}

	@Override
	public void sendSpotifyUpgradeEmail(SpotifyUserUpgradeSubmitRecord.Status status, String email) {
		try {
			SimpleMailMessage msg = new SimpleMailMessage();
			if (status == SpotifyUserUpgradeSubmitRecord.Status.success) {
				msg.setSubject("【崇宇信息】Spotify开通成功");
				msg.setText("尊敬的用户，您申请Spotify个人车已成功开通，您可登录银河官网查看车票https://nf.video。");
			} else {
				msg.setSubject("【崇宇信息】Spotify开通失败");
				msg.setText("尊敬的用户，您申请Spotify个人车因账号密码错误开通失败，您可登录银河官网https://nf.video，在车票页修改提交的账号密码。");
			}
			msg.setFrom(from);
			msg.setTo(email);
			mailSender.send(msg);
		} catch (Exception e) {
			log.error("发送用户邮件：{}  spotify升级邮件失败:{}", email, StringUtil.getErrorText(e));
		}
	}

	private void sendMsgIfFailRetry(JavaMailSenderImpl sender, MimeMessage msg) {
		try {
			sender.send(msg);
			log.info("发送课件成功");
		} catch (Exception e) {
			log.error("发送课件失败失败,error:{}", StringUtil.getErrorText(e));
			if (!retry(msg)) {
				throw BusinessRuntimeException.getInstance("暂无可用邮件服务器");
			}
		}
	}

	public Boolean retry(MimeMessage msg) {
		for (JavaMailSenderImpl retry : senders) {
			try {
				msg.setFrom(retry.getUsername());
				retry.send(msg);
				log.info("重试发送课件成功");
				return true;
			} catch (Exception e2) {
				log.error("重试发送课件失败失败,error:{}", StringUtil.getErrorText(e2));
			}
		}
		return false;
	}

	public JavaMailSenderImpl getJavaEmailServer() throws Exception {
		if (senders.isEmpty()) {
			String key = "reEmailSenders";
			if (redisService.setNx(key, "reEmailSenders", 30l)) {
				if (senders.isEmpty()) {
					init();
					redisService.del(key);
				}
			} else {
				if (senders.isEmpty()) {
					throw BusinessRuntimeException.getInstance("系统超时,请重新获取邮箱验证码..");
				}
			}
		}
		int i = ThreadLocalRandom.current().nextInt(senders.size());
		return senders.get(i);
	}

	public boolean sendMail(String toAddress, String subject, String text) {
		SimpleMailMessage msg = new SimpleMailMessage();
		msg.setFrom(from);
		msg.setTo(toAddress);
		msg.setSubject(subject);
		msg.setText(text);
		try {
			mailSender.send(msg);
		} catch (MailException ex) {
			log.error(ex.getMessage());
			return false;
		}
		return true;
	}
}
