package com.infoepoch.pms.dispatchassistant.controller.basic;

import com.infoepoch.pms.dispatchassistant.common.component.BaseController;
import com.infoepoch.pms.dispatchassistant.common.component.RedisTool;
import com.infoepoch.pms.dispatchassistant.common.component.Result;
import com.infoepoch.pms.dispatchassistant.common.component.SnowFlake;
import com.infoepoch.pms.dispatchassistant.common.constant.RedisKeys;
import com.infoepoch.pms.dispatchassistant.common.constant.StoreKeys;
import com.infoepoch.pms.dispatchassistant.common.exception.NotLoginException;
import com.infoepoch.pms.dispatchassistant.common.exception.ValidationException;
import com.infoepoch.pms.dispatchassistant.common.utils.*;
import com.infoepoch.pms.dispatchassistant.domain.basic.organization.Organization;
import com.infoepoch.pms.dispatchassistant.domain.basic.organization.OrganizationRoot;
import com.infoepoch.pms.dispatchassistant.domain.basic.store.KeyValueStoreService;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.User;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.UserService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/auth")
public class AuthController extends BaseController {

    private final static Logger logger = LoggerFactory.getLogger(AuthController.class);

    @Autowired
    private Auth auth;
    @Autowired
    private UserService userService;
    @Autowired
    private KeyValueStoreService keyValueStoreService;
    @Autowired
    private RedisTool redisTool;

    @Autowired
    private DecodeJWTToken decodeJWTToken;


    /**
     * 登录
     *
     * @param param
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/login")
    public Result login(String param, HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.isBlank(param))
            throw new ValidationException("登录参数不可为空");
        String decodeStr = Base64Utils.decode(param);
        Map<String, Object> paramMap = JsonUtils.jsonToMap(decodeStr);
        if (paramMap.get("captcha") == null)
            throw new ValidationException("验证码不可为空");
        if (paramMap.get("username") == null)
            throw new ValidationException("登录账号不可为空");
        if (paramMap.get("password") == null)
            throw new ValidationException("密码不可为空");
        String captcha = String.valueOf(paramMap.get("captcha"));
        String sign = ServletTool.getSign();
        if (StringUtils.isBlank(sign)) {
            sign = SnowFlake.instant().nextId().toString();

            Cookie cookie = new Cookie(RedisKeys.SIGN, sign);
            cookie.setPath(request.getContextPath());
            response.addCookie(cookie);
        }
        String redisCaptcha = redisTool.get(RedisKeys.CAPTCHA_LOGIN + sign);
        if (!captcha.equals(redisCaptcha)) {
            throw new ValidationException("验证码错误");
        }
        redisTool.remove(RedisKeys.CAPTCHA_LOGIN + sign);
        String username = String.valueOf(paramMap.get("username"));
        String password = String.valueOf(paramMap.get("password"));
        User user = userService.getByAuth(username, password);
        // 用户信息失效时间：2小时
        redisTool.put(RedisKeys.AUTHED_USER + sign, JsonUtils.objectToJson(user), 2, TimeUnit.HOURS);
        String userAgent = request.getHeader("user-agent");
        logger.info(String.format("用户姓名：%s,浏览器版本：%s", user.getDisplayName(), userAgent));
        Map<String, Object> map = new HashMap<>();
        map.put("uuid", user.getId());
        map.put("username", user.getUsername());
        map.put("name", user.getDisplayName());
        map.put("mainPageUri", getMainPageUri());
        return Result.successData(map);
    }

    /**
     * mock登录
     *
     * @param userId
     * @return
     */
    @PostMapping("/mock/login")
    public Result mockLogin(String userId, HttpServletRequest request, HttpServletResponse response) {
        User user = userService.getUserById(userId);
        if (user == null) {
            throw new ValidationException("不存在的用户");
        } else {
            String sign = ServletTool.getSign();
            if (StringUtils.isBlank(sign)) {
                sign = SnowFlake.instant().nextId().toString();
                Cookie cookie = new Cookie(RedisKeys.SIGN, sign);
                cookie.setPath(request.getContextPath());
                response.addCookie(cookie);
            }
            // 用户信息失效时间：2小时
            redisTool.put(RedisKeys.AUTHED_USER + sign, JsonUtils.objectToJson(user), 2, TimeUnit.HOURS);
        }
        return Result.successData(user);
    }

    /**
     * 获取首页跳转地址
     *
     * @return
     */
    private String getMainPageUri() {
        String uri = keyValueStoreService.queryValueByKey(StoreKeys.MAIN_PAGE_URI);
        if (StringUtils.isBlank(uri))
            uri = "/pages/main/main.html";
        return uri;
    }

    /**
     * 注销
     */
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    @ResponseBody
    public Result logout() {
        User user = auth.getUser();
        if (user != null) {
            String sign = ServletTool.getSign();
            redisTool.remove(RedisKeys.AUTHED_USER + sign);
        }
        return Result.success();
    }

    /**
     * 获取当前用户
     *
     * @return
     */
    @GetMapping("/current-user")
    public Result currentUser() throws NotLoginException {
        User user = auth.getUserReq();
        user.setBranchCompanyFlag(OrganizationRoot.judgeBranchCompany(user.getOrganizationId()));
        return Result.successData(user);
    }

    /**
     * 当前用户所属部门
     *
     * @return
     * @throws NotLoginException
     */
    @GetMapping("/current-department")
    public Result currentDepartment() throws NotLoginException {
        User user = auth.getUserReq();
        Organization department = OrganizationRoot.getDepartmentById(user.getOrganizationId());
        return Result.successData(department);
    }

    /**
     * 当前用户所属分公司
     *
     * @return
     * @throws NotLoginException
     */
    @GetMapping("/current-company")
    public Result currentCompany() throws NotLoginException {
        User user = auth.getUserReq();
        Organization company = OrganizationRoot.getCompanyById(user.getOrganizationId());
        return Result.successData(company);
    }

    /**
     * 图形验证码
     *
     * @param request
     * @param response
     */
    @RequestMapping("/captcha")
    public void captcha(HttpServletRequest request, HttpServletResponse response) {
        // 生成验证码表达式，确保大于0
        generateCaptchaExpress(request, response);
    }

    /**
     * 从OA单点到该系统
     * 从微服务单点到该系统
     *
     * @return
     */
    @GetMapping("/epmsSSO")
    public void epmsSSO(HttpServletResponse response, HttpServletRequest request) {
        try {
            //获取cookie解析token,接口获取用户id
            //epms系统单点的cookie是pms-web;OA单点过来的cookie是ObSSOCookie
            String userName = decodeJWTToken.getUserName(request);
            logger.info("get userId from cookie = " + userName);
            //设置Session
            if (userName == null) {
                throw new ValidationException("单点登录异常，无法获取当前用户信息。");
            }
            User user = userService.selectByUsername(userName.toLowerCase());
            if (user == null)
                throw new ValidationException("单点登录异常，无法获取当前用户信息。");
            String sign = ServletTool.getSign();
            if (StringUtils.isBlank(sign)) {
                sign = SnowFlake.instant().nextId().toString();
                Cookie cookie = new Cookie(RedisKeys.SIGN, sign);
                cookie.setPath(request.getContextPath());
                response.addCookie(cookie);
            }
            redisTool.put(RedisKeys.AUTHED_USER + sign, JsonUtils.objectToJson(user), 2, TimeUnit.HOURS);
            String userAgent = request.getHeader("user-agent");
            logger.info(String.format("用户姓名：%s,浏览器版本：%s", user.getDisplayName(), userAgent));
//            response.sendRedirect(mainPage);
            String mainURI = keyValueStoreService.queryValueByKey(StoreKeys.GXAPP_MAIN_PAGE_URI);
            response.sendRedirect(mainURI);
        } catch (Exception e) {
            throw new ValidationException("epmsSSO单点登录异常");
        }
    }

    /**
     * 从低代码单点到该系统跳转到智能体
     * 从微服务单点到该系统
     *
     * @return
     */
    @GetMapping("/assistantSSO")
    public void assistantSSO(HttpServletResponse response, HttpServletRequest request) {
        try {
            //获取cookie解析token,接口获取用户id
            //epms系统单点的cookie是pms-web;OA单点过来的cookie是ObSSOCookie
            String userName = decodeJWTToken.getUserName(request);
            logger.info("get userId from cookie = " + userName);
            //设置Session
            if (userName == null) {
                throw new ValidationException("单点登录异常，无法获取当前用户信息。");
            }
            User user = userService.selectByUsername(userName.toLowerCase());
            if (user == null)
                throw new ValidationException("单点登录异常，无法获取当前用户信息。");
            String sign = ServletTool.getSign();
            if (StringUtils.isBlank(sign)) {
                sign = SnowFlake.instant().nextId().toString();
                Cookie cookie = new Cookie(RedisKeys.SIGN, sign);
                cookie.setPath(request.getContextPath());
                response.addCookie(cookie);
            }
            redisTool.put(RedisKeys.AUTHED_USER + sign, JsonUtils.objectToJson(user), 2, TimeUnit.HOURS);
            String userAgent = request.getHeader("user-agent");
            logger.info(String.format("用户姓名：%s,浏览器版本：%s", user.getDisplayName(), userAgent));
//            response.sendRedirect(mainPage);
            String mainURI = keyValueStoreService.queryValueByKey(StoreKeys.GXAPP_ASSISTANT_PAGE_URI);
            response.sendRedirect(mainURI);
        } catch (Exception e) {
            throw new ValidationException("epmsSSO单点登录异常");
        }
    }

    @GetMapping("/app-check")
    public Result appCheck(HttpServletResponse response, HttpServletRequest request) {
        try {
            //获取cookie解析token,接口获取用户id
            //epms系统单点的cookie是pms-web;OA单点过来的cookie是ObSSOCookie
            String userName = decodeJWTToken.getUserName(request);
            logger.info("get userId from cookie = " + userName);
            //设置Session
            if (userName == null) {
                throw new ValidationException("单点登录异常，无法获取当前用户信息。");
            }
            User user = userService.selectByUsername(userName.toLowerCase());
            if (user == null)
                throw new ValidationException("单点登录异常，无法获取当前用户信息。");
            String sign = ServletTool.getSign();
            if (StringUtils.isBlank(sign)) {
                sign = SnowFlake.instant().nextId().toString();
                String para = URLEncoder.encode(sign, "UTF-8");
                Cookie cookie = new Cookie(RedisKeys.SIGN, para);
                cookie.setPath(request.getContextPath());
                response.addCookie(cookie);
            }
            redisTool.put(RedisKeys.AUTHED_USER + sign, JsonUtils.objectToJson(user), 2, TimeUnit.HOURS);
            String userAgent = request.getHeader("user-agent");
            logger.info(String.format("用户姓名：%s,浏览器版本：%s", user.getDisplayName(), userAgent));
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("sign", sign);
            return Result.successData(resultMap);
        } catch (Exception e) {
            throw new ValidationException("epmsSSO单点登录异常");
        }
    }

    /**
     * 生成验证码表达式，确保大于0
     * 回调自身
     *
     * @param request
     * @param response
     * @return
     */
    private int generateCaptchaExpress(HttpServletRequest request, HttpServletResponse response) {
        int result = 0;
        SecureRandom random;
        try{
            random = SecureRandom.getInstance("SHA1PRNG");
        }catch (Exception e){
            throw new ValidationException("随机数获取失败");
        }
        int num1 = (int) (random.nextDouble() * 10 + 1);
        int num2 = (int) (random.nextDouble() * 10 + 1);
        int num3 = (int) (random.nextDouble() * 10 + 1);
        int fuhao = random.nextInt(3);//产生一个[0,2]之间的随机整数
        //记录符号
        String fuhaostr = null;
        String fuhaostr2 = null;
        switch (fuhao) {
            case 0:
                fuhaostr = "+";
                fuhaostr2 = "+";
                result = num1 + num2 + num3;
                break;
            case 1:
                fuhaostr = "-";
                fuhaostr2 = "-";
                result = num1 - num2 - num3;
                break;
            case 2:
                fuhaostr = "x";
                fuhaostr2 = "-";
                result = num1 * num2 - num3;
                break;
            case 3:
                fuhaostr = "+";
                fuhaostr2 = "x";
                result = num1 + num2 * num3;
                break;
            case 4:
                fuhaostr = "-";
                fuhaostr2 = "x";
                result = num1 - num2 * num3;
                break;
            case 5:
                fuhaostr = "x";
                fuhaostr2 = "+";
                result = num1 * num2 + num3;
                break;
            //case 3 : fuhaostr = "/";result = num1 / num2;break;
        }
        // 如果结果小于0，重新生成
        if (result < 0)
            return generateCaptchaExpress(request, response);

        // 获取sign
        String sign = ServletTool.getSign();
        if (StringUtils.isBlank(sign)) {
            sign = SnowFlake.instant().nextId().toString();
            Cookie cookie = new Cookie(RedisKeys.SIGN, sign);
            cookie.setPath(request.getContextPath());
            response.addCookie(cookie);
        }
        // 验证码失效时间：5分钟
        redisTool.put(RedisKeys.CAPTCHA_LOGIN + sign, String.valueOf(result), 5, TimeUnit.MINUTES);
        //拼接算术表达式,用户图片显示。
        String calc = num1 + " " + fuhaostr + " " + num2 + " " + fuhaostr2 + " " + num3 + " = ?";
        writeCaptchaImage(response, calc);
        return result;
    }

    /**
     * 写验证码图片
     *
     * @param response
     * @param calc     验证码表达式
     */
    private void writeCaptchaImage(HttpServletResponse response, String calc) {
        int width = 190;
        int height = 30;
        //在内存中创建图片
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //创建图片的上下文
        Graphics2D g = image.createGraphics();
        //设置背景
        g.setColor(CaptcaUtils.getRandomColor(240, 250));
        //设置字体
        g.setFont(new Font("微软雅黑", Font.PLAIN, 22));
        //开始绘制
        g.fillRect(0, 0, width, height);
        SecureRandom random;
        try{
            random = SecureRandom.getInstance("SHA1PRNG");
        }catch (Exception e){
            throw new ValidationException("随机数获取失败");
        }
        //干扰线的绘制，绘制线条到图片中
        g.setColor(CaptcaUtils.getRandomColor(60, 235));
        for (int i = 0; i < 20; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int x1 = random.nextInt(60);
            int y1 = random.nextInt(60);
            g.drawLine(x, y, x1, y1);
        }
        g.setColor(new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256)));
        for (int i = 0; i < 800; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            g.drawOval(x, y, 1, 1);
        }
        //设置随机颜色
        g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
        //绘制表达式
        g.drawString(calc, 15, 25);
        //结束绘制
        g.dispose();
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            //输出图片到页面
            ImageIO.write(image, "jpg", out);
            response.setHeader("Cache-Control", "no-store");
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpeg");
            out.flush();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (out != null)
                    out.close();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

}
