package cn.meowrain.aioj.backend.userservice.service.impl;

import cn.meowrain.aioj.backend.framework.core.exception.ClientException;
import cn.meowrain.aioj.backend.framework.core.exception.ServiceException;
import cn.meowrain.aioj.backend.userservice.common.constants.RedisKeyConstants;
import cn.meowrain.aioj.backend.userservice.service.EmailService;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;

/**
 * 邮件服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EmailServiceImpl implements EmailService {

    private final JavaMailSender mailSender;

    private final StringRedisTemplate redisTemplate;

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

    private static final String SUBJECT = "【AIOJ】邮箱验证码";


    private static final int CODE_LENGTH = 6;

    /**
     * 生成6位随机验证码
     */
    private String generateCode() {
        SecureRandom random = new SecureRandom();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < CODE_LENGTH; i++) {
            stringBuilder.append(random.nextInt(10));
        }
        return stringBuilder.toString();
    }
    /**
     * 构建邮件内容
     */
    private String buildEmailContent(String code) {
        return String.format("""
        <html>
        <body style="font-family: Arial, Helvetica, 'Microsoft YaHei', sans-serif; background-color: #f4f6f8; margin: 0; padding: 0;">
            <table width="100%%" cellpadding="0" cellspacing="0" style="padding: 30px 0;">
                <tr>
                    <td align="center">
                        <table width="600" cellpadding="0" cellspacing="0" style="background: #ffffff; border-radius: 6px; box-shadow: 0 2px 6px rgba(0,0,0,0.06);">
                            <tr>
                                <td style="padding: 24px 32px; border-bottom: 1px solid #e6e8eb;">
                                    <h2 style="margin: 0; font-size: 20px; font-weight: 600; color: #1f2937;">AIOJ 邮箱验证</h2>
                                </td>
                            </tr>

                            <tr>
                                <td style="padding: 24px 32px; color: #374151; font-size: 14px;">
                                    <p style="margin: 0 0 12px 0;">您好，</p>
                                    <p style="margin: 0 0 16px 0;">您正在进行邮箱安全校验，为保障账户安全，请使用以下验证码：</p>
                                
                                    <div style="background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 6px; padding: 16px; text-align: center; margin: 20px 0;">
                                        <span style="font-size: 28px; font-weight: bold; letter-spacing: 2px; color: #2563eb;">%s</span>
                                    </div>

                                    <p style="margin: 0 0 16px 0;">验证码有效期为 <strong>1 分钟</strong>，请尽快完成操作。</p>
                                    <p style="margin: 0 0 8px 0; color: #6b7280;">若非本人操作，请忽略本邮件。</p>
                                </td>
                            </tr>

                            <tr>
                                <td style="padding: 20px 32px; border-top: 1px solid #e6e8eb; background: #fafbfc; color: #9ca3af; font-size: 12px; text-align: center;">
                                    <p style="margin: 0 0 4px 0;">此邮件由系统自动发送，请勿回复</p>
                                    <p style="margin: 0;">AIOJ © %s All Rights Reserved.</p>
                                </td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </body>
        </html>
        """, code, java.time.Year.now());
    }


    @Async("emailExecutor")
    @Override
    public void sendVerifyCode(String email) {
        // 生成验证码
        String code = generateCode();
        // 验证码存redis里面，1分钟过期时间
        String redisKey = String.format(RedisKeyConstants.EMAIL_CODE_PREFIX,email);
        redisTemplate.opsForValue().set(redisKey,code,RedisKeyConstants.EMAIL_CODE_TTL,TimeUnit.SECONDS);

        // 发送邮件
        try {
            MimeMessage message = mailSender.createMimeMessage();
            // ⭐ 显式指定 UTF-8 编码，解决中文乱码问题
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
            helper.setFrom(FROM_EMAIL,"AIOJ");
            helper.setTo(email);
            helper.setSubject(SUBJECT);
            helper.setText(buildEmailContent(code), true);

            // ⭐ 发送邮件
            mailSender.send(message);
            log.info("验证码邮件发送成功: 邮箱={}, 验证码={}", email, code);
        }catch (MessagingException e) {
            log.error("验证码邮件发送失败: 邮箱={}", email, e);
            throw new ServiceException("邮件发送失败,请稍后重试");
        } catch (UnsupportedEncodingException e) {
            throw new ServiceException("邮件发送失败,请稍后重试");
        }
    }


    /**
     * 获取邮箱验证码
     * @param email 收件人邮箱
     * @return 验证码
     */
    @Override
    public String getVerifyCode(String email) {
        String redisKey = String.format(RedisKeyConstants.EMAIL_CODE_PREFIX,email);
        // 从redis里面获取验证码,用Object接收,因为redis里面可能存储的是null 比如过期这种情况
        Object verifyCodeInSystem = redisTemplate.opsForValue().get(redisKey);
        if(verifyCodeInSystem == null) {
            throw new ClientException("验证码不存在或已过期");
        }
        // 转换为字符串
        return verifyCodeInSystem.toString();
    }

}
