package com.slodon.b2b2c.controller.member.front;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.slodon.b2b2c.core.controller.BaseController;
import com.slodon.b2b2c.core.response.JsonResult;
import com.slodon.b2b2c.core.response.SldResponse;
import com.slodon.b2b2c.vo.member.QrCodeLoginProgressVO;
import com.slodon.b2b2c.vo.member.QrCodeLoginVO;
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.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.Hashtable;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author slodon
 */
@Api(tags = "front-app扫码授权登录")
@RestController
@RequestMapping("v3/member/front/qr/login")
@Slf4j
public class QrCodeLoginController extends BaseController {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @ApiOperation("生成二维码")
    @GetMapping("createQr")
    public JsonResult<QrCodeLoginVO> createQr(HttpServletRequest request) throws Exception {
        //生成一个随机标识
        String uuid = UUID.randomUUID().toString();

        //二维码属性
        Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
        // 内容所使用字符集编码
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
        hints.put(EncodeHintType.MARGIN, 1);
        //二维码
        BitMatrix bitMatrix = new MultiFormatWriter().encode(uuid, BarcodeFormat.QR_CODE, 300, 300, hints);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix,"png",bos);
        bos.flush();
        bos.close();
        String image = Base64.getEncoder().encodeToString(bos.toByteArray());

        QrCodeLoginVO vo = new QrCodeLoginVO();
        vo.setImage(image);
        vo.setU(uuid);

        //将标识存入redis，5分钟过期时间,授权成功后，将 accessToken 存入value中
        stringRedisTemplate.opsForValue().set(uuid,"0",5L,TimeUnit.MINUTES);

        return SldResponse.success(vo);
    }

    @ApiOperation("生成二维码后轮询此接口查看授权进度")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "u", value = "授权登录标识")
    })
    @PostMapping("progress")
    public JsonResult<QrCodeLoginProgressVO> progress(HttpServletRequest request, @RequestParam(value = "u") String u){
        String refreshToken = stringRedisTemplate.opsForValue().get(u);
        QrCodeLoginProgressVO vo = new QrCodeLoginProgressVO();
        if (StringUtils.isEmpty(refreshToken)){
            //二维码过期
            vo.setProgress(QrCodeLoginProgressVO.PROGRESS_INVALID);
            return SldResponse.success(vo);
        }

        if ("0".equals(refreshToken)){
            //还未授权
            vo.setProgress(QrCodeLoginProgressVO.PROGRESS_WAIT);
            return SldResponse.success(vo);
        }

        //授权成功
        vo.setProgress(QrCodeLoginProgressVO.PROGRESS_SUCCESS);
        vo.setRefreshToken(refreshToken);
        return SldResponse.success(vo);
    }

    @ApiOperation("app授权")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "u", value = "授权登录标识"),
            @ApiImplicitParam(name = "refreshToken", value = "登录令牌")
    })
    @PostMapping("grant")
    public JsonResult<Object> grant(HttpServletRequest request,
                            @RequestParam(value = "u") String u,
                            @RequestParam(value = "refreshToken") String refreshToken){
        String s = stringRedisTemplate.opsForValue().get(u);
        if (StringUtils.isEmpty(s)){
            //二维码过期
            return SldResponse.fail("二维码已失效");
        }

        if (!"0".equals(s)){
            //已授权,重复扫码，提示失效
            return SldResponse.fail("二维码已失效");
        }

        //将令牌存入redis，防止网络延迟，重新设置5分钟的过期时间
        stringRedisTemplate.opsForValue().set(u,refreshToken,5L,TimeUnit.MINUTES);

        return SldResponse.success("授权成功");
    }
}
