package org.jeecg.modules.shop.captcha.util;

import cn.hutool.core.lang.Assert;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@RequiredArgsConstructor
public class EmailUtil {

    @Value("${aliyun.email.limit.single-of-hour}")
    private int singleEmailLimitOfHour;
    @Value("${aliyun.email.limit.single-of-day}")
    private int singleEmailLimitOfDay;
    @Value("${aliyun.email.limit.total-of-hour}")
    private int totalEmailLimitOfHour;
    @Value("${aliyun.email.limit.total-of-day}")
    private int totalEmailLimitOfDay;
    
    @Resource(name = "partner_MailAccount")
    private MailAccount account;
    
    private final RedisTemplate<String, String> redisTemplate;

    private static final String TYPE_LOGIN = "登录";
    private static final String TITLE_LOGIN = "Your EJET Spark Code Is %s";
    private static final String CT_LOGIN = "Welcome! Enter this code within the next 10 minutes to log in:\n" +
            "%s" +"<br/><br/>"+
            "You're receiving this email because you are creating or logging in to your EJET Spark account. " +
            "This email isnot a marketing or promotional email. That is why this email does not contain an unsubscribe link." +
            " lf youhave any problems logging in, please contact us via spark@ejet.com for help.";



    private static final String TYPE_NOTIFIED = "合作伙伴审核通知";
    private static final String TITLE_NOTIFIED = "EJET 供应商协同平台";
    private static final String CT_NOTIFIED = "您提交的s%供应商信息已通过，请及时登录平台进行产品/品牌录入 https://supplier.ejetgroup.com/login";



    public void sendRegisterEmail(String email,String captcha) {
        sendEmail(email, String.format(TITLE_LOGIN,captcha), String.format(CT_LOGIN, captcha), TYPE_LOGIN);
    }
    


    public void sendNotifiedEmail(String email, String supplierName) {
        sendEmail(email, TITLE_NOTIFIED, String.format(CT_NOTIFIED, supplierName), TYPE_NOTIFIED);
    }


    
    private void sendEmail(String email, String title, String content, String type) {
        Assert.isFalse(isTriggerSendFrequencyLimit(email), "触发发送频率限制,请稍后重试");
        try {
            log.info("发送{}邮件，邮箱={}", type, email);
            MailUtil.send(account, email, title, content, true);
            onEmailSendSuccess(email);
            log.info("邮件发送成功");
        } catch (Exception e) {
            log.error("邮件发送失败，邮箱={}，错误信息={}", email, e.getMessage());
        }
    }

    private boolean isTriggerSendFrequencyLimit(String email) {
        Boolean isLock = redisTemplate.opsForValue().setIfAbsent(generateSendFrequencyLimitKey(email, TimeUnit.MINUTES), "1", 1, TimeUnit.MINUTES);
        if (!Boolean.TRUE.equals(isLock)) {
            return true;
        }
        List<String> values = redisTemplate.opsForValue().multiGet(Arrays.asList(
                generateSendFrequencyLimitKey(email, TimeUnit.HOURS),
                generateSendFrequencyLimitKey(email, TimeUnit.DAYS),
                generateSendFrequencyLimitKey(null, TimeUnit.HOURS),
                generateSendFrequencyLimitKey(null, TimeUnit.DAYS)));
        if (values == null) {
            log.error("redis访问异常，values == null");
        }
        int hourCount = values.get(0) == null ? 0 : Integer.parseInt(values.get(0));
        int dayCount = values.get(1) == null ? 0 : Integer.parseInt(values.get(1));
        int totalHourCount = values.get(2) == null ? 0 : Integer.parseInt(values.get(2));
        int totalDayCount = values.get(3) == null ? 0 : Integer.parseInt(values.get(3));
        if (hourCount >= singleEmailLimitOfHour || dayCount >= singleEmailLimitOfDay) {
            return true;
        }
        if (totalEmailLimitOfHour > 0 && totalHourCount >= totalEmailLimitOfHour) {
            log.error("邮件全局发送量触发小时级限额，当前限额值={}", totalEmailLimitOfHour);
            return true;
        }
        if (totalEmailLimitOfDay > 0 && totalDayCount >= totalEmailLimitOfDay) {
            log.error("邮件全局发送量触发天级限额，当前限额值={}", totalEmailLimitOfDay);
            return true;
        }
        return false;
    }

    private void onEmailSendSuccess(String email) {
        String script = "redis.call('INCR', KEYS[1])\nredis.call('EXPIRE', KEYS[1], 3600)\n" +
                "redis.call('INCR', KEYS[2])\nredis.call('EXPIRE', KEYS[2], 86400)\n" +
                "redis.call('INCR', KEYS[3])\nredis.call('EXPIRE', KEYS[3], 3600)\n" +
                "redis.call('INCR', KEYS[4])\nredis.call('EXPIRE', KEYS[4], 86400)";
        DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class);
        redisTemplate.execute(redisScript, Arrays.asList(
                generateSendFrequencyLimitKey(email, TimeUnit.HOURS),
                generateSendFrequencyLimitKey(email, TimeUnit.DAYS),
                generateSendFrequencyLimitKey(null, TimeUnit.HOURS),
                generateSendFrequencyLimitKey(null, TimeUnit.DAYS)));
    }

    private String generateSendFrequencyLimitKey(String email, TimeUnit timeUnit) {
        String timeUnitStr;
        switch (timeUnit) {
            case MINUTES:
                timeUnitStr = "F";
                break;
            case HOURS:
                timeUnitStr = String.valueOf(LocalDateTime.now().getHour());
                break;
            case DAYS:
                timeUnitStr = String.valueOf(LocalDate.now().getDayOfMonth());
                break;
            default:
                throw new IllegalArgumentException();
        }
        return String.format("email:limit:%s:%s", timeUnitStr, email != null ? SecureUtil.md5(email) : "total");
    }
    
}
