package cn.wisenergy.web.admin.controller.app;

import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.wisenergy.common.constant.RedisConsts;
import cn.wisenergy.common.enums.ResultEnum;
import cn.wisenergy.common.utils.*;
import cn.wisenergy.mapper.UsersMapper;
import cn.wisenergy.model.app.User;
import cn.wisenergy.model.dto.UsersDto;
import cn.wisenergy.model.vo.UserLoginVo;
import cn.wisenergy.model.vo.UserRegisterVo;
import cn.wisenergy.service.app.LoginService;
import cn.wisenergy.service.app.UserService;
import cn.wisenergy.web.shiro.JwtUtil;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by m1991 on 2021/3/2 13:35
 *
 * @author 86187
 */
@Api(tags = "登录/注册")
@Slf4j
@RequestMapping("api/user")
@RestController
public class LoginController {


    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private UserService usersService;

    @Autowired
    private LoginService loginService;

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 手机登录接口
     *
     * @param userId 用户id
     * @param sms    短信验证码
     * @return 返回结果
     * @throws Exception 异常
     */

    @ApiOperation(value = "登录", notes = "登录", httpMethod = "POST", produces = "application/json;charset=UTF-8")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "sms", value = "验证码", dataType = "String"),
            @ApiImplicitParam(name = "userId", value = "用户手机号", required = true, dataType = "String")})
    @RequestMapping("/login")
    public Map loginBySms(@RequestParam String userId, @RequestParam String sms) throws Exception {
        User users = null;
        Map map = new HashMap();
        String key = StringUtil.formatKeyWithPrefix(Constants.RedisKey.PROJECT_PRIFIX, Constants.RedisKey.SMS_PRIFIX, userId, Constants.Sms.CodeType.LOGIN_OR_REGISTER + "");
        String redisCode = redisUtils.getValue(key);
        if (StringUtil.isBlank(redisCode) || !sms.equals(redisCode)) {

            map.put("code", "1003");
            map.put("msg", "验证码错误");
            return map;
        }
        redisUtils.delete(key);
        //根据手机号判断用户是否存在
        //不存在则保存用户信息--修改为提示用户注册
        users = usersService.queryUsersByPhone(userId);


        if (null == users) {
            map.put("code", "1005");
            map.put("msg", "账号不存在,请注册");
            return map;
        }
        String token = null;

        token = createToken(users);

        if (!StringUtil.isBlank(token)) {
            String wyz = users.getInviteCode();
            Map<String, Object> map1 = StringUtil.createSimpleMap("token", token);
            map1.put("wyz", wyz);
            map1.put("code", 0);
            map1.put("msg", "成功！");
            return map1;
        }
        return (Map) ResultUtils.returnFail();
    }


    public String createToken(User users) throws Exception {
        String token = StringUtil.createToken();
        //保存token
        String tokenKey = StringUtil.formatKeyWithPrefix(Constants.RedisKey.PROJECT_PRIFIX, Constants.RedisKey.TOKEN_PRIFIX, token);
        UsersDto usersDto = new UsersDto();
        BeanUtils.copyProperties(users, usersDto);
        redisUtils.set(tokenKey, JSONObject.toJSONString(usersDto), Constants.Duration.ONE_MONTH_HOUR_INT);
        return token;
    }

    @ApiOperation(value = "获取用户登录token信息", notes = "获取用户登录token信息", httpMethod = "POST", produces = "application/json; charset=UTF-8")
    @PostMapping("/info")
    public Result info(HttpServletRequest request) throws Exception {
        String token = request.getHeader("token");
        String tokenKey = StringUtil.formatKeyWithPrefix(Constants.RedisKey.PROJECT_PRIFIX, Constants.RedisKey.TOKEN_PRIFIX, token);
        String userDtoJson = redisUtils.getValue(tokenKey);
        if (StringUtil.isBlank(userDtoJson)) {
            Map map = new HashMap();
            map.put("code", "2001");
            map.put("msg", "未登录");
            return ResultUtils.returnFail("未登录");
        }
        UsersDto usersDto = JSONObject.parseObject(userDtoJson, UsersDto.class);
        return ResultUtils.returnDataSuccess(usersDto);
    }

    @ApiOperation(value = "二维码邀请注册", notes = "二维码邀请注册", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户手机号", required = true, dataType = "String")
    })
    @GetMapping(value = "/registerByQrCode")
    public ResponseEntity<byte[]> registerByQrCode(@RequestParam("userId") String userId,
                                                   @RequestParam(value = "width", required = false, defaultValue = "120") int width,
                                                   @RequestParam(value = "height", required = false, defaultValue = "120") int height,
                                                   HttpServletRequest request) throws IOException {
        User user = this.usersService.getByUserId(userId);
        if (user != null) {
            String regFullUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
                    + "/front/register?beInvitedCode=" + user.getInviteCode();
            final InputStream is = new ClassPathResource("templates/background.jpg").getInputStream();
            BufferedImage srcImage = ImageIO.read(is);

            QrConfig config = new QrConfig(width, height);
            config.setCharset(StandardCharsets.UTF_8);
            config.setMargin(0);
            config.setWidth(width);
            config.setHeight(height);
            BufferedImage waterImage = QrCodeUtil.generate(regFullUrl, config);
            byte[] bytes = ImageUtil.watermarkImageSimple1(srcImage, waterImage);
//            ByteArrayOutputStream out = new ByteArrayOutputStream();
//            ImageIO.write(waterImage, "jpg", out);
//            byte[] bytes = out.toByteArray();

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.IMAGE_JPEG);
            headers.setContentLength(bytes.length);
            return new ResponseEntity<>(bytes, headers, HttpStatus.OK);
        }
        return null;
    }

    @ApiOperation(value = "用户注册", notes = "用户注册", httpMethod = "POST", produces = "application/json; charset=UTF-8")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户手机号", required = true, dataType = "String"),
            @ApiImplicitParam(name = "beInvitedCode", value = "推荐人邀请码", required = false, dataType = "String"),
            @ApiImplicitParam(name = "sms", value = "验证码", required = true, dataType = "String")
    })
    @RequestMapping("/register")
    public Map register(@RequestParam String userId, @RequestParam String beInvitedCode, @RequestParam String sms) throws Exception {
        User users = null;
        String key = StringUtil.formatKeyWithPrefix(Constants.RedisKey.PROJECT_PRIFIX, Constants.RedisKey.SMS_PRIFIX, userId, Constants.Sms.CodeType.LOGIN_OR_REGISTER + "");
        String redisCode = redisUtils.getValue(key);
        if (StringUtil.isBlank(redisCode) || !sms.equals(redisCode)) {
            Map map = new HashMap();
            map.put("code", "1003");
            map.put("msg", "验证码错误");
            return map;
        }
        redisUtils.delete(key);
        //判断phone是否符合输入类型
        if (!userId.matches(Constants.RegConstant.PHONE_REGSTR)) {
            Map map = new HashMap();
            map.put("code", "1008");
            map.put("msg", "手机号码格式不正确");
            return map;
        }

        return usersService.userByZx(userId, beInvitedCode);
    }

    /**
     * 退出登录
     *
     * @param
     * @return
     */
    @ApiOperation(value = "退出登录", produces = "application/json", notes = "退出登录")
    @ApiImplicitParam(paramType = "header", name = "token", value = "用户token", required = true, dataType = "String")
    @PostMapping("/logout")
    public Result logout(HttpServletRequest request) {

        log.info("退出登录");
        Result result = ResultUtils.returnFail();
        String token = request.getHeader("token");
        String key = RedisKeyUtils.formatKeyWithPrefix(Constants.Redis.PREFIX_TOKEN, token);
        if (redisUtils.getValue(key) == null) {
            log.info("要退出登录的用户未登录");
            return ResultUtils.returnResult(ResultEnum.FILE_NOT_LOGIN);
        }
        int succ = usersService.logout(token);
        if (succ > 0) {
            result = ResultUtils.returnSuccess();
        }
        return result;
    }


    @ApiOperation(value = "用户注册", notes = "用户注册", httpMethod = "POST")
    @ApiImplicitParam(name = "userVo", value = "用户信息", dataType = "UserRegisterVo")
    @PostMapping("/userRegister")
    public R<Boolean> userRegister(@RequestBody UserRegisterVo userVo) {
        log.info("shop-mall[]LoginController[]userRegister[]input.param.userVo:" + userVo);
        if (null == userVo || StringUtils.isBlank(userVo.getUserId()) || StringUtils.isBlank(userVo.getSms())) {
            return R.error("入参不能为空!");
        }
        return loginService.userRegister(userVo);
    }


    @ApiOperation(value = "用户登录-返回token", notes = "用户登录-返回token", httpMethod = "POST")
    @ApiImplicitParam(name = "userVo", value = "用户登录信息", dataType = "UserLoginVo")
    @PostMapping("/userLogin")
    public R<String> userLogin(@RequestBody UserLoginVo userVo) {
        log.info("shop-mall[]LoginController[]userLogin[]input.param.userVo:" + userVo);
        if (null == userVo || StringUtils.isBlank(userVo.getUserId()) || StringUtils.isBlank(userVo.getSms())) {
            return R.error("入参不能为空!");
        }

        //判断phone是否符合输入类型
        if (!userVo.getUserId().matches(Constants.RegConstant.PHONE_REGSTR)) {
            return R.error("手机号码格式不正确!");
        }

        //1、检验验证码是否正确
        String key = StringUtil.formatKeyWithPrefix(Constants.RedisKey.PROJECT_PRIFIX, Constants.RedisKey.SMS_PRIFIX,
                userVo.getUserId(), Constants.Sms.CodeType.LOGIN_OR_REGISTER + "");
        String redisCode = redisUtils.getValue(key);
        if (StringUtils.isBlank(redisCode) || !userVo.getSms().equals(redisCode)) {
            return R.error("验证码错误!");
        }

        //2、检验用户手机号是否存在
        User user = usersMapper.getByUserId(userVo.getUserId());
        if (null == user || StringUtils.isBlank(user.getUserId())) {
            return R.error("账户不存在,请注册!");
        }

        //3、获取token
        // 创建token
        String token = jwtUtil.generateToken(user);

        // 保存Redis
        redisTemplate.opsForValue().set(RedisConsts.JWT_ACCESS_TOKEN + token, token);
        return R.ok(token);
    }

}
