package com.sien.common.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sien.common.entity.AppUser;
import com.sien.common.service.AppSmsService;
import com.sien.common.service.AppUserService;
import com.sien.common.sms.SendSms;
import com.sien.common.vo.AppUserQueryVo;
import com.sien.common.vo.SmsCode;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Arrays;

@Service
@Slf4j
public class AppSmsServiceImpl implements AppSmsService {
    @Autowired
    private AppUserService appUserService;

    /**
     * 获取当前环境
     */
    @Value("${spring.profiles.active}")
    private String profiles;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 测试环境
     */
    private static final String DEV_PROFILE = "dev";

    /**
     * 测试环境默认短信验证码
     */
    private static final String DEFAULT_DEV_SMS_CODE = "666666";

    /**
     * 注册 短信验证码redis的key值
     */
    private static final String SMS_REGIEST = "sms:app:register:%s_%s";

    /**
     * 修改 短信验证码redis的key值
     */
    private static final String SMS_UPDATE = "sms:app:update:%s_%s";

    /**
     * 修改 短信验证码redis的key值,新手机
     */
    private static final String SMS_UPDATE_NEW = "sms:app:updateNew:%s_%s";

    /**
     * 短信验证码redis的key值
     */
    private static final String SMS_LOGIN = "sms:app:login:%s_%s";

    @Override
    public void deleteRegisterCode(String area, String number) {
        redisTemplate.delete(String.format(SMS_REGIEST, area, number));
    }

    @Override
    public void deleteUpdatePhoneCode(String area, String number) {
        redisTemplate.delete(String.format(SMS_UPDATE, area, number));

    }

    @Override
    public void deleteUpdatePhoneCodeNew(String area, String number) {
        redisTemplate.delete(String.format(SMS_UPDATE_NEW, area, number));

    }

    @Override
    public ApiResult<Object> registerOrLoginCode(String area, String number) {
        return getSmsCodeApiResult(String.format(SMS_REGIEST, area, number), area, number);
    }

    @Override
    public ApiResult<Object> updatePhoneCodeSendToOld() throws Exception {
        JwtToken jwtToken = (JwtToken) SecurityUtils.getSubject().getPrincipal();
        AppUserQueryVo appUserById = appUserService.getAppUserById(jwtToken.getUserId());

        // 向旧手机发送验证码
        String key = String.format(SMS_UPDATE, appUserById.getPhoneArea(), appUserById.getPhone());
        ApiResult<Object> smsCodeApiResult = getSmsCodeApiResult(key, appUserById.getPhoneArea(), appUserById.getPhone());
        return smsCodeApiResult;
    }

    @Override
    public ApiResult<Object> updatePhoneCodeSendToNew(String phoneArea, String phone) {

        // 判断手机号是否已经注册
        AppUser one = appUserService.getOne(new QueryWrapper<AppUser>().lambda()
                .eq(AppUser::getPhoneArea, phoneArea)
                .eq(AppUser::getPhone, phone));
        if (one != null) {
            return ApiResult.fail(ApiCode.UPDATA_PHONE_USE, null);
        }

        // 向新手机发送验证码
        String key = String.format(SMS_UPDATE_NEW, phoneArea, phone);
        ApiResult<Object> smsCodeApiResult = getSmsCodeApiResult(key, phoneArea, phone);
        return smsCodeApiResult;
    }

    @Override
    public ApiResult<Boolean> checkPhoneCodeOld(String code) throws Exception {

        JwtToken jwtToken = (JwtToken) SecurityUtils.getSubject().getPrincipal();
        AppUserQueryVo appUserById = appUserService.getAppUserById(jwtToken.getUserId());

        boolean equalsRegisterCode = this.equalsUpdatePhoneCodeOld(appUserById.getPhoneArea(), appUserById.getPhone(), code);

        if (!equalsRegisterCode) {
            return ApiResult.fail(ApiCode.SMS_CODE_ERROR);
        }
        return ApiResult.ok();

    }

    /**
     * 获取短信验证码
     *
     * @param key
     * @param area
     * @param number
     * @return
     */
    private ApiResult<Object> getSmsCodeApiResult(String key, String area, String number) {

        // 生成验证码code
        String randomCode = getRandomCode();

        // 过期时间(秒)
        long expire = 120L;
        Duration expireDuration = Duration.ofSeconds(expire);
        // 存至redis
        redisTemplate.opsForValue().set(key, randomCode, expireDuration);

        SmsCode smsCode = new SmsCode();
        smsCode.setSmsCode(randomCode);
        log.info(area + "," + number + ":" + randomCode);

        // 调用短信平台发送短信代码 2020年09月30日09:48:42
        try {
            SendSms.send("+" + area + number, randomCode);
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResult.fail(ApiCode.FAIL, null);
        }

        return ApiResult.ok(null);
    }

    @Override
    public ApiResult LoginType(String area, String number) {
        return getSmsCodeApiResult(String.format(SMS_LOGIN, area, number), area, number);
    }

    @Override
    public boolean equalsRegisterCode(String area, String number, String code) {
        return equalsSms(SMS_REGIEST, area, number, code);
    }

    @Override
    public boolean equalsUpdatePhoneCodeOld(String area, String number, String code) {
        return equalsSms(SMS_UPDATE, area, number, code);
    }

    @Override
    public boolean equalsUpdatePhoneCodeNew(String area, String number, String code) {

        return equalsSms(SMS_UPDATE_NEW, area, number, code);

    }

    private boolean equalsSms(String type, String area, String number, String code) {
        String formatKey = String.format(type, area, number);

        Object key = redisTemplate.opsForValue().get(formatKey);

        if (key == null) {
            return false;
        }

        return String.valueOf(key).equals(code);
    }

    @Override
    public boolean equalsLoginCode(String area, String number, String code) {
        return equalsSms(SMS_LOGIN, area, number, code);
    }

    /**
     * 生成验证码code
     *
     * @return
     */
    String getRandomCode() {
        // 如果为测试环境则生成默认
        if (profiles.equals(DEV_PROFILE) || profiles.equals("test")) {
            return DEFAULT_DEV_SMS_CODE;
        } else {
            return Arrays.toString(RandomUtil.randomInts(6));
        }
    }


}
