package com.oauth.system.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.oauth.mapper.UUserMapper;
import com.oauth.utils.RandImageUtil;
import com.framework.core.response.StarBosResult;
import com.framework.core.utils.MD5Util;
import com.framework.core.utils.RedisUtil;
import com.oauth.system.model.SysLoginModel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Api(tags = "ApiAuth")
@RestController
@RequestMapping("/auth")
//@CrossOrigin
public class ApiAuthController {

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";

    @Value("${security.oauth2.client.client-id}")
    private String clientId;

    @Value("${security.oauth2.client.client-secret}")
    private String clientSecret;

    @Value("${security.oauth2.client.access-token-uri}")
    private String accessTokenUri;

    @Autowired
    private UUserMapper uuserMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RestTemplate restTemplate;


    @ApiOperation("登陆")
    @PostMapping(value = "/login")
    public StarBosResult<?> login(SysLoginModel sysLoginModel, @RequestHeader HttpHeaders httpHeaders) throws Exception {
        StarBosResult<JSONObject> result = new StarBosResult<JSONObject>();
        System.out.println("laile" + sysLoginModel);
        MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
        paramsMap.set("grant_type", "password");
        String username = sysLoginModel.getUsername();
        paramsMap.set("username", username);
        String password = sysLoginModel.getPassword();
        paramsMap.set("client_id", clientId);
        paramsMap.set("client_secret", clientSecret);
        paramsMap.set("scope", "all");
        String code = sysLoginModel.getCode();
        if (code == null) {
            result.error500("请输入验证码");
            return result;
        }

        try {
            paramsMap.set("password", password);
        } catch (Exception e) {
            return StarBosResult.fail("密码有误");
        }

        String lowerCaseCode = code.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCode, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        //当进入登录页时，有一定几率出现验证码错误 #1714
        //校验验证码
        if (checkCode == null) {
            result.error500("验证码无效");
            return result;
        } else if (!checkCode.toString().equals(lowerCaseCode)) {
            result.error500("验证码错误");
            return result;
        }
        // 使用客户端的请求头,发起请求
        httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // 强制移除 原来的请求头,防止token失效
        httpHeaders.remove(HttpHeaders.AUTHORIZATION);
        //构造请求实体和头
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity(paramsMap, httpHeaders);
        JSONObject authInfo = null;
        try {
            authInfo = restTemplate.postForObject(accessTokenUri, request, JSONObject.class);
        } catch (HttpClientErrorException e) {
            e.printStackTrace();
            System.out.println("发生异常");
            if (e.getStatusCode().equals(HttpStatus.BAD_REQUEST)) {
                byte[] bs = e.getResponseBodyAsByteArray();
                String msg = new String(bs, "utf-8");
                log.info(msg);
                Map<String, String> mm = (Map<String, String>) JSON.parse(msg);
                log.info(mm.get("error_description"));
                return StarBosResult.fail(mm.get("error"), mm.get("error_description"));
            } else {
                return StarBosResult.fail("登录失败");
            }
        }
        log.info("\r\n"+authInfo);
        Integer id = uuserMapper.findIdByUsername(username);
        String token = authInfo.getString("value");
        Integer expires_in = (Integer) authInfo.get("expiresIn");
        Map<String, Object> jwtMap = new HashMap<>();
        jwtMap.put("id", id);
        jwtMap.put("expireTime", expires_in);
        jwtMap.put("token", "bearer " + token);
        redisUtil.del(realKey);
        redisUtil.set(username, token, expires_in);
        return StarBosResult.ok(jwtMap);
    }
    /**
     * 后台生成图形验证码 ：有效
     *
     * @param response
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/getCaptcha")
    public StarBosResult<String> randomImage(HttpServletResponse response) {
        StarBosResult<String> res = new StarBosResult<String>();
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();//转小写
            String realKey = MD5Util.MD5Encode(lowerCaseCode, "utf-8");
            log.info("\r\n"+"随机:" + code);
            log.info("\r\n"+"验证码:" + code);
            redisUtil.set(realKey, lowerCaseCode, 600);//10分钟
            String base64 = RandImageUtil.generate(code);
            res.setCode(1);
            res.setData(base64);
            res.setMsg("验证码获取成功");
        } catch (Exception e) {
            res.error500("获取验证码出错", e.getMessage());
            e.printStackTrace();
        }
        return res;
    }


    /**
     * 返回ArrayBuffer类型图片
     *
     * @param response
     */
    @Deprecated
    @PostMapping(value = "getCaptchaImage")
    public void getCaptchaImage(HttpServletResponse response) {
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(100, 40, 4, 6);
        BufferedImage bufferedImage = captcha.getImage();
        response.setContentType("image/jpeg");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setHeader("Pragma", "no-cache");
        response.setCharacterEncoding("UTF-8");
        // ByteArrayOutputStream(captcha.getImageBytes())
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();

            String code = captcha.getCode();
            log.info("\r\n"+captcha.getCode());
            //放入缓存,此处需要

            ImageIO.write(bufferedImage, "jpeg", outputStream);

        } catch (IOException e) {

            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                ;
            }
        }

    }

    /**
     * 返回base64图片字符串，注意返回类型
     *
     * @param response
     * @return
     */
//    @PostMapping(value = "getCaptcha")
    @Deprecated
    public String getCaptcha(HttpServletResponse response) {
        LineCaptcha captcha = CaptchaUtil.createLineCaptcha(100, 40, 4, 6);
        BufferedImage bufferedImage = captcha.getImage();
        response.setContentType("image/jpeg");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setHeader("Pragma", "no-cache");
        response.setCharacterEncoding("UTF-8");


        String code = captcha.getCode();
        System.out.println(captcha.getCode());
        //放入缓存,此处需要

        return captcha.getImageBase64Data();

    }

    public static OAuth2AccessToken login(String url, String clientId, String clientSecret, String username, String password) {
        ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails();
        resourceDetails.setAccessTokenUri(url);
        resourceDetails.setClientId(clientId);
        resourceDetails.setClientSecret(clientSecret);
        resourceDetails.setUsername(username);
        resourceDetails.setPassword(password);
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
        restTemplate.setAccessTokenProvider(new ResourceOwnerPasswordAccessTokenProvider());
        return restTemplate.getAccessToken();
    }
}
