package com.chushang.gateway.service.impl;

import cn.hutool.core.codec.Base64;
import com.chushang.common.core.constant.Constants;
import com.chushang.common.core.exception.ResultException;
import com.chushang.common.core.util.IdUtils;
import com.chushang.common.core.util.StringUtils;
import com.chushang.common.core.web.AjaxResult;
import com.chushang.gateway.config.properties.CaptchaProperties;
import com.chushang.gateway.service.ValidateCodeService;
import com.google.code.kaptcha.Producer;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.FastByteArrayOutputStream;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * 验证码实现处理
 */
@Slf4j
@Service
public class ValidateCodeServiceImpl implements ValidateCodeService {
    @Resource(name = "captchaProducer")
    private Producer captchaProducer;

    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private CaptchaProperties captchaProperties;

    /**
     * 生成验证码
     */
    @Override
    public AjaxResult createCaptcha() throws ResultException {
        boolean captchaOnOff = captchaProperties.getEnabled();
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("captchaEnabled", captchaOnOff);
        if (captchaOnOff) {
            // 保存验证码信息
            String uuid = IdUtils.getId(32);
            String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;

            String capStr, code = null;
            BufferedImage image = null;

            String captchaType = captchaProperties.getType();
            // 生成验证码
            if ("math".equals(captchaType)) {
                String capText = captchaProducerMath.createText();
                capStr = capText.substring(0, capText.lastIndexOf("@"));
                code = capText.substring(capText.lastIndexOf("@") + 1);
                image = captchaProducerMath.createImage(capStr);
            } else if ("char".equals(captchaType)) {
                code = capStr = captchaProducer.createText();
                image = captchaProducer.createImage(capStr);
            }
            redissonClient.getBucket(verifyKey)
                    .set(code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
            // 转换流信息写出
            FastByteArrayOutputStream os = new FastByteArrayOutputStream();
            try {
                assert image != null;
                ImageIO.write(image, "jpg", os);
            } catch (IOException e) {
                return AjaxResult.error(e.getMessage());
            }
            resultMap.put("uuid", uuid);
            resultMap.put("img", Base64.encode(os.toByteArray()));
        }
        return AjaxResult.success(resultMap);
    }

    /**
     * 校验验证码
     */
    @SneakyThrows
    @Override
    public void checkCaptcha(String code, String uuid) throws ResultException, ExecutionException, InterruptedException {
        if (!"chushang".equals(code)) {
            if (StringUtils.isEmpty(code)) {
                throw new ResultException("验证码不能为空");
            }
            if (StringUtils.isEmpty(uuid)) {
                throw new ResultException("验证码已失效");
            }
            String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;

            RBucket<String> bucket = redissonClient.getBucket(verifyKey);
            String captcha = bucket.getAndDelete();
            if (!code.equalsIgnoreCase(captcha)) {
                throw new ResultException("Verification code error");
            }
        }
    }
}
