package cn.qinys.platform.base.service;


import cn.qinys.platform.base.constants.BaseConstants;
import cn.qinys.platform.base.exceptions.BizException;
import cn.qinys.platform.base.redis.RedisKeyEnum;
import cn.qinys.platform.base.utils.RedisUtils;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;


import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 验证码 的服务实现类
 *
 * @author v-lishiquan.gx@chinatelecom.cn
 * @date 2019-12-27
 */
@Service
@Slf4j
public class CaptchaServiceImpl implements ICaptchaService {

    @Resource
    private DefaultKaptcha defaultKaptcha;
    @Resource
    private RedisUtils redisUtils;

    @Override
    public Map<String, String> render(String type) {
        String key = UUID.randomUUID().toString().replaceAll("-", "");

        if (BaseConstants.CaptchaTypeCons.ARITHMETIC_CAPTCHA.getCode().equalsIgnoreCase(type)) {
            return this.generateArithmeticCaptcha(key);
        }
        return this.generateWordCaptcha(key);
    }

    @Override
    public boolean validate(String captchaKey, String captchaCode) {
        if (!StringUtils.hasLength(captchaKey)) {
            return false;
        }
        String key = RedisKeyEnum.CAPTCHA.getCode() + captchaKey;
        Object captchaText = redisUtils.get(key);
        redisUtils.delete(key);
        if (Objects.isNull(captchaText)) {
            return false;
        }
        return captchaCode.equalsIgnoreCase(captchaText.toString());
    }

    private Map<String, String> generateWordCaptcha(String key) {
        String code = defaultKaptcha.createText().toUpperCase();
        return this.generateCode(key, code, code);
    }

    private Map<String, String> generateArithmeticCaptcha(String key) {
        int result;
        Random random = new Random();
        StringBuilder number = new StringBuilder();
        int xx = random.nextInt(10);
        int yy = random.nextInt(10);
        // 0~3 对应加减乘除
        int round = (int) Math.round(Math.random() * 3);
        BaseConstants.CalcTypeCons calcTypeCons = BaseConstants.CalcTypeCons.values()[round];
        number.append(yy);
        switch (calcTypeCons) {
            case PLUS:
                result = yy + xx;
                number.append(calcTypeCons.getDesc());
                break;
            case MINUS:
                result = yy - xx;
                number.append(calcTypeCons.getDesc());
                break;
            case MULTI:
                result = yy * xx;
                number.append(calcTypeCons.getDesc());
                break;
            default:
                if (xx != 0 && yy % xx == 0) {
                    result = yy / xx;
                    number.append(calcTypeCons.getDesc());
                } else {
                    result = yy + xx;
                    number.append(BaseConstants.CalcTypeCons.PLUS.getDesc());
                }
        }
        number.append(xx);
        number.append(" = ?");
        return this.generateCode(key, number.toString(), String.valueOf(result));
    }

    private Map<String, String> generateCode(String key, String picContent, String value) {
        try {
            BufferedImage captchaImage = defaultKaptcha.createImage(picContent);
            // 生成BASE64
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(captchaImage, "jpg", outputStream);
            String base64Img = this.encodeBase64(outputStream.toByteArray());
            redisUtils.set(RedisKeyEnum.CAPTCHA.getCode() + key, value, RedisKeyEnum.CAPTCHA.getExpireTime());
            //返回给用户的验证码图片
            Map<String, String> imgMap = new ConcurrentHashMap<>();
            imgMap.put(key, "data:image/jpeg;base64," + base64Img);
            return imgMap;
        } catch (IOException ex) {
            throw new BizException("生成验证码错误");
        }
    }

    private String encodeBase64(byte[] input) {
        return new String(Base64.encodeBase64(input));
    }


}
