package cn.reghao.tnb.auth.app.service;

import cn.reghao.jutil.jdk.web.result.Result;
import cn.reghao.jutil.jdk.security.RandomString;
import cn.reghao.tnb.common.util.StringRegexp;
import cn.reghao.tnb.auth.app.model.constant.VerifyChannel;
import cn.reghao.tnb.auth.app.model.dto.VerifyCodeDto;
import cn.reghao.tnb.auth.app.db.repository.AccountRepository;
import cn.reghao.tnb.auth.app.config.rabbitmq.RabbitProducer;
import cn.reghao.tnb.auth.app.model.po.UserAccount;
import cn.reghao.tnb.auth.app.model.po.UserRegistry;
import cn.reghao.jutil.jdk.media.CaptchaUtil;
import cn.reghao.tnb.auth.app.config.redis.RedisKeys;
import cn.reghao.tnb.auth.app.config.redis.ds.RedisString;
import cn.reghao.tnb.message.api.constant.NotifyType;
import cn.reghao.tnb.message.api.dto.msg.VerifyMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author reghao
 * @date 2022-04-26 20:24:58
 */
@Slf4j
@Service
public class CodeService {
    private final RabbitProducer rabbitProducer;
    private final RedisString redisString;
    private final long sessionTimeout;
    private final AccountRepository accountRepository;

    public CodeService(RabbitProducer rabbitProducer, RedisString redisString, ServerProperties serverProperties,
                       AccountRepository accountRepository) {
        this.rabbitProducer = rabbitProducer;
        this.redisString = redisString;
        this.sessionTimeout = serverProperties.getServlet().getSession().getTimeout().getSeconds();
        this.accountRepository = accountRepository;
    }

    public InputStream generateCaptcha() throws IOException {
        String captchaCode;
        UserRegistry userRegistry = accountRepository.getUserRegistry();
        if (!userRegistry.getEnableCaptcha()) {
            captchaCode = RandomString.getString(5);
        } else {
            captchaCode = userRegistry.getCaptchaCode();
        }
        redisString.setWithTimeout(RedisKeys.getCaptchaKey(), captchaCode, sessionTimeout);

        ByteArrayOutputStream baos = CaptchaUtil.captchaWithDisturb(captchaCode, 130, 48);
        return new ByteArrayInputStream(baos.toByteArray());
    }

    public String getCaptcha() {
        return redisString.get(RedisKeys.getCaptchaKey());
    }

    public Result sendVerifyCode(VerifyCodeDto verifyCodeDto) {
        Integer channel = verifyCodeDto.getChannel();
        String receiver = verifyCodeDto.getReceiver();

        int type;
        if (StringRegexp.matchEmail(receiver)) {
            type = NotifyType.email.getValue();
        } else if (StringRegexp.matchMobile(receiver)) {
            type = NotifyType.mobile.getValue();
        } else {
            return Result.fail("邮箱/手机号格式错误");
        }

        UserRegistry userRegistry = accountRepository.getUserRegistry();
        if (channel == VerifyChannel.registryChannel.getValue()) {
            if (!userRegistry.getEnabled()) {
                return Result.fail("系统当前未开放注册");
            } else {
                UserAccount userAccount = null;
                if (type == NotifyType.email.getValue()) {
                    userAccount = accountRepository.getUserAccountByEmail(receiver);
                } else if (type == NotifyType.mobile.getValue()) {
                    userAccount = accountRepository.getUserAccountByMobile(receiver);
                }

                if (userAccount != null) {
                    return Result.fail("帐号已存在");
                }
            }
        }

        String code;
        if (userRegistry.getEnableVerify()) {
            code = userRegistry.getVerifyCode();
        } else {
            code = RandomString.getNumber(6);
        }

        redisString.setWithTimeout(RedisKeys.getVerifyCodeKey(channel, receiver), code, sessionTimeout);

        String title = "验证码";
        VerifyMessage verifyMessage = new VerifyMessage(title, code, receiver);
        rabbitProducer.sendVerifyMessage(verifyMessage);
        return Result.success("验证码已发送, 请及时查收");
    }

    public String getVerifyCode(int channel, String receiver) {
        return redisString.get(RedisKeys.getVerifyCodeKey(channel, receiver));
    }
}
