package org.springblade.modules.auth.endpoint;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springblade.auth.model.SmsLogin;
import org.springblade.auth.sms.SmsLoginAuth;
import org.springblade.common.cache.CacheNames;
import org.springblade.core.constant.AppConstant;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.utils.WebUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.exception.ServiceException;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.message.model.SmsInfo;
import org.springblade.modules.auth.enums.UserEnum;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.system.entity.*;
import org.springblade.modules.system.enums.SmsCategory;
import org.springblade.modules.system.service.ISystemBaseInfoService;
import org.springblade.modules.system.service.ITenantService;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.service.normal.SmsService;
import org.springblade.modules.system.vo.SystemBaseInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.*;

@RestController
@RequestMapping(AppConstant.APPLICATION_AUTH_NAME + "/sms")
@Slf4j
@Api(value = "短信验证登录", tags = "短信验证登录接口")
public class BladeSmsEndPoint{

    @Autowired
    private IUserService userService;

    @Autowired
    private ITenantService tenantService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private BladeRedis bladeRedis;

    @Autowired
    private ISystemBaseInfoService systemBaseInfoService;


    @GetMapping("/send")
    @ApiOperation(value = "发送短信验证码",notes = "传入电话号tell;电话号的KEY:header['Phone-Key']")
    private Kv sendMsm(@ApiParam(value = "手机号") @RequestParam(required = false) String tell){
        // 校验登录方式是否被允许
        SystemBaseInfoVO systemBaseInfoVO = systemBaseInfoService.getSystemBaseInfoVO();
//        if (!systemBaseInfoVO.getLoginType().contains("2")) {
//            throw new ServiceException("系统未配置短信登录方式...");
//        }
        // 使用随机数生成短信验证码
        String tellKey = WebUtil.getRequest().getHeader(TokenUtil.PHONE_HEADER_KEY);
        String phone = tell;
        // 如果手机号为空或者包含*则说明有加密需要去缓存中获取手机号
        if (StrUtil.isEmpty(tell) || tell.contains("*")){
            phone = bladeRedis.get(CacheNames.PHONE_KEY + tellKey);
        }
        // 获取短信模板
        List<Sms> smsList = smsService.list(Wrappers.<Sms>lambdaQuery()
                .eq(Sms::getBusinessClassify,1)
                .eq(Sms::getStatus,1)
                .orderByAsc(Sms::getCreateTime));
        if (CollectionUtil.isEmpty(smsList)){
            smsList = smsService.getList(1);
            if (CollectionUtil.isEmpty(smsList)) {
                throw new ServiceException("未查询到短信模板，请检查短信模板是否配置...");
            }
        }
        Sms sms = smsList.get(0);

        SmsInfo smsInfo = SmsInfo.builder().accessKey(sms.getAccessKey()).secretKey(sms.getSecretKey()).signName(sms.getSignName())
                .regionId(sms.getRegionId()).appId(sms.getAppId()).templateId(sms.getTemplateId()).build();

        SmsLogin smsLogin = SmsLogin.builder()
                .category(sms.getCategory().getValue()).templateParams(sms.getTemplateParams()).phone(phone).build();
        SmsLoginAuth smsLoginAuth = SpringUtil.getBean(SmsLoginAuth.class);
        String msg = smsLoginAuth.sendMsg(smsInfo,smsLogin);

        if (msg.contains("200")) {
            String key = UUID.randomUUID().toString();
            // 存入redis并设置过期时间为5分钟
            bladeRedis.setEx(CacheNames.SMS_CODE_KEY + key, msg.split(",")[1], Duration.ofMinutes(5));
            return Kv.create().set("ok",true).set("key", key);
        } else {
            throw new ServiceException("验证码发送失败");
        }
    }


    @GetMapping("/failure")
    @ApiOperation(value = "验证码失效",notes = "传入短信验证码的KEY:header['Phone-Msg-Key']")
    public R<Boolean> failureSmsCode(){
        String key = WebUtil.getRequest().getHeader(TokenUtil.PHONE_SMS_KEY);

        return R.data(bladeRedis.del(CacheNames.SMS_CODE_KEY + key));
    }

    @GetMapping("/chack")
    @ApiOperation(value = "校验验证码",notes = "传入电话号tell；验证码code；短信验证码的KEY:header['Phone-Msg-Key']，电话号的KEY:header['Phone-Key']")
    public R<Boolean> checkSms(@ApiParam(value = "验证码") @RequestParam(required = false) String code) {

        String key = WebUtil.getRequest().getHeader(TokenUtil.PHONE_SMS_KEY);
        // 从redis中获取短信验证码
        String sms = bladeRedis.get(CacheNames.SMS_CODE_KEY + key);
        if (!sms.equals(code)){
            // 删除短信验证码
            bladeRedis.del(CacheNames.SMS_CODE_KEY + key);
            throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT);
        }
        // 删除短信验证码
        bladeRedis.del(CacheNames.SMS_CODE_KEY + key);
        return R.data(true);
    }



    @GetMapping("/login")
    @ApiOperation(value = "短信登录",notes = "传入电话号tell；验证码code；短信验证码的KEY:header['Phone-Msg-Key']，电话号的KEY:header['Phone-Key']")
    public Kv smsToken(@ApiParam(value = "手机号") @RequestParam(required = false) String tell,
                       @ApiParam(value = "验证码") @RequestParam(required = false) String code){

        // 校验登录方式是否被允许
        SystemBaseInfoVO systemBaseInfoVO = systemBaseInfoService.getSystemBaseInfoVO();
        if (!systemBaseInfoVO.getLoginType().contains("2")) {
            throw new ServiceException("系统未配置短信登录方式...");
        }

        Kv authInfo = Kv.create();
        String key = WebUtil.getRequest().getHeader(TokenUtil.PHONE_SMS_KEY);
        String sms = bladeRedis.get(CacheNames.SMS_CODE_KEY + key);
        if (StrUtil.isEmpty(sms)){
            throw new ServiceException("验证码过期,请重新发送");
        }
//        String code = WebUtil.getRequest().getHeader(TokenUtil.PHONE_HEADER_CODE);
        if (!sms.equals(code)){
            throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT);
        }
        String phone = tell;
        // 如果手机号为空或者包含*则说明有加密需要去缓存中获取手机号 PHONE_HEADER_KEY
        String tellKey = null;
        if (StrUtil.isEmpty(tell) || tell.contains("*")){
            tellKey = WebUtil.getRequest().getHeader(TokenUtil.PHONE_HEADER_KEY);
            phone = bladeRedis.get(CacheNames.PHONE_KEY + tellKey);

        }
        List<User> users = userService.list(new LambdaQueryWrapper<User>()
                .eq(User::getPhone, phone)
                .eq(User::getIsDeleted, 0)
                .orderByAsc(User::getCreateTime));

        if (CollectionUtil.isEmpty(users)) {
            return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "用户不存在");
        }

        UserInfo userInfo = grant(users.get(0));

        if (userInfo == null || userInfo.getUser() == null) {
            return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "用户名或密码不正确");
        }

        if (Func.isEmpty(userInfo.getRoles())) {
            return authInfo.set("error_code", HttpServletResponse.SC_BAD_REQUEST).set("error_msg", "未获得用户的角色信息");
        }
        // 删除redis中缓存的电话信息
        if (StrUtil.isNotEmpty(tellKey)){
            bladeRedis.del(CacheNames.PHONE_KEY + tellKey);
        }
        String loginType = systemBaseInfoVO.getLoginType();
        // 判断当前的多登录方式是否为第一个登录方式
//        if (loginType.split(",").length > 1 && loginType.split(",")[0].equals("2")){
//
//            return authInfo.set("ok",true);
//        }
        return TokenUtil.createAuthInfo(userInfo);
    }

    public UserInfo grant(User user) {
        String tenantId = user.getTenantId();
        String username = user.getAccount();
        String password = user.getPassword();
        UserInfo userInfo = null;
        if (StrUtil.isNotBlank(username) && StrUtil.isNotBlank(password)) {
            // 获取租户信息
            Tenant tenant = tenantService.getByTenantId(tenantId);
            if (TokenUtil.judgeTenant(tenant)) {
                throw new ServiceException(TokenUtil.USER_HAS_NO_TENANT_PERMISSION);
            }
            // 根据不同用户类型调用对应的接口返回数据，用户可自行拓展
//            userInfo = userService.userInfo(tenantId, username, password, UserEnum.WEB);

            // 根据不同用户类型调用对应的接口返回数据，用户可自行拓展
            // 获取用户类型
            String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);
            if (userType.equals(UserEnum.WEB.getName())) {
                userInfo = userService.userInfo(tenantId, username, password, UserEnum.WEB);
            } else if (userType.equals(UserEnum.APP.getName())) {
                userInfo = userService.userInfo(tenantId, username, password, UserEnum.APP);
            } else {
                userInfo = userService.userInfo(tenantId, username, password, UserEnum.OTHER);
            }
        }
        return userInfo;
    }
}
