package com.wms.controller;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wms.annotation.MyLog;
import com.wms.constants.enums.ResponseCode;
import com.wms.entity.app.dto.KateUser;
import com.wms.entity.app.dto.MenuDto;
import com.wms.entity.app.dto.UserDto;
import com.wms.entity.app.request.UserQuery;
import com.wms.entity.app.vo.MenuEntity;
import com.wms.entity.app.ResponseEntity;
import com.wms.entity.app.vo.UserConfigEntity;
import com.wms.entity.table.User;
import com.wms.service.MenuService;
import com.wms.service.StandService;
import com.wms.service.UserService;
import com.wms.constants.WmsConstants;
import com.wms.utils.HttpUtils;
import com.wms.utils.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;

import java.util.LinkedList;
import java.util.List;

import static com.wms.utils.StringUtils.convertJsonString;

/**
 * WMS用户控制类
 * @author 梁州
 * &#064;date  2023/2/14
 */
@Controller
@CrossOrigin
@RequestMapping(value = "/wms/user")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UserController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 请求头部信息
     */
    private final HttpServletRequest servletRequest;
    /**
     * 用户服务
     */
    private final UserService userService;
    /**
     * 菜单服务
     */
    private final MenuService menuService;
    /**
     * 站台服务
     */
    private final StandService standService;

    /**
     * 带密码登录
     * @param userQuery 用户
     * @return 结果
     */
    @PostMapping("/loginWithAuth")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    @MyLog(logTitle = "带密码登录", logMethod = "loginWithAuth")
    public String loginWithAuth(@RequestBody UserQuery userQuery) {
        logger.info("请求登录，登录账户名：{}，登录ip：{}", userQuery.getLoginAccount(), HttpUtils.getIpAddr(servletRequest));
        // 创建响应信息
        ResponseEntity rsp = new ResponseEntity();
        try {
            if (StringUtils.isEmpty(userQuery.getLoginAccount())) {
                logger.error("请输入用户名");
                // 返回错误
                rsp.setCode(ResponseCode.ERROR.getCode());
                rsp.setMessage("请输入用户名");
                return convertJsonString(rsp);
            }
            // 验证用户信息
            UserDto validatedUser = userService.validateUser(userQuery.toUserPO(), true);
            if (validatedUser == null || StringUtils.isEmpty(validatedUser.getLoginAccount())) {
                logger.error("登录错误，用户不存在或密码错误");
                // 返回错误
                rsp.setCode(ResponseCode.ERROR.getCode());
                rsp.setMessage("登录错误，用户不存在或密码错误");
                return convertJsonString(rsp);
            }

            // 返回成功
            logger.info("登录成功，登录账户名：{}", validatedUser.getLoginAccount());
            rsp.setCode(ResponseCode.OK.getCode());
            rsp.setMessage("登录成功");
            // 返回用户数据
            rsp.setReturnData(generateUserInfo(validatedUser, HttpUtils.getIpAddr(servletRequest)));
            return convertJsonString(rsp);
        } catch (Exception e) {
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            logger.info("数据库错误：{}", convertJsonString(e));
            // 返回其他异常
            rsp.setCode(ResponseCode.ERROR.getCode());
            rsp.setMessage("登录异常");
            return convertJsonString(rsp);
        }
    }

    /**
     * 无密码登录
     * @param userQuery 用户
     * @return 结果
     */
    @PostMapping("/loginWithoutAuth")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    @MyLog(logTitle = "无密码登录", logMethod = "loginWithoutAuth")
    public String loginWithoutAuth(@RequestBody UserQuery userQuery) {
        logger.info("请求无密码登录，登录账户名：{}，登录ip：{}", userQuery.getLoginAccount(), HttpUtils.getIpAddr(servletRequest));
        // 创建响应信息
        ResponseEntity rsp = new ResponseEntity();
        try {
            if (StringUtils.isEmpty(userQuery.getLoginAccount())) {
                logger.error("请输入用户名");
                // 返回错误
                rsp.setCode(ResponseCode.ERROR.getCode());
                rsp.setMessage("请输入用户名");
                return convertJsonString(rsp);
            }
            // 验证用户信息
            UserDto validatedUser = userService.validateUser(userQuery.toUserPO(), false);
            if (validatedUser == null || StringUtils.isEmpty(validatedUser.getLoginAccount())) {
                logger.error("登录错误，用户不存在或密码错误");
                // 返回错误
                rsp.setCode(ResponseCode.ERROR.getCode());
                rsp.setMessage("登录错误，用户不存在或密码错误");
                return convertJsonString(rsp);
            }

            // 返回成功
            logger.info("登录成功，登录账户名：{}", validatedUser.getLoginAccount());
            rsp.setCode(ResponseCode.OK.getCode());
            rsp.setMessage("登录成功");
            // 返回用户数据
            rsp.setReturnData(generateUserInfo(validatedUser, HttpUtils.getIpAddr(servletRequest)));
            return convertJsonString(rsp);
        } catch (Exception e) {
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            logger.info("数据库错误：{}", convertJsonString(e));
            // 返回其他异常
            rsp.setCode(ResponseCode.ERROR.getCode());
            rsp.setMessage("登录异常");
            return convertJsonString(rsp);
        }
    }

    /**
     * 获得用户信息菜单
     * @param codeInfo code信息
     * @return 结果
     */
    @PostMapping("/getUser")
    @ResponseBody
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    @MyLog(logTitle = "获得用户信息菜单", logMethod = "getUser")
    public String getUser(@RequestBody JSONObject codeInfo) {
        logger.info("卡特账号请求登录，登录信息：{}，登录ip：{}", convertJsonString(codeInfo), HttpUtils.getIpAddr(servletRequest));
        // 响应信息
        ResponseEntity rsp = new ResponseEntity();
        String idToken = codeInfo.getString("id_token");
        logger.info("卡特登录回调，idToken：{}", idToken);
        if (StringUtils.isEmpty(idToken)) {
            logger.error("ID_TOKEN为空");
            // 返回其他异常
            rsp.setCode(ResponseCode.ERROR.getCode());
            rsp.setMessage("ID_TOKEN为空");
            return JSON.toJSONString(rsp);
        }
        try {
            // 解码token
            DecodedJWT decodedJWT = JWT.decode(idToken);
            // 创建用户信息
            KateUser kateUser = new KateUser();
            kateUser.setName(decodedJWT.getClaim("name").asString());
            kateUser.setGroups(decodedJWT.getClaim("groups").asList(String.class));
            // 卡特用户信息映射本地用户信息
            User newUser = new User();
            newUser.setUserName(kateUser.getName());
            List<User> localUsers = userService.list(new LambdaQueryWrapper<User>()
                    .eq(User::getUserName, kateUser.getName()));
            if (localUsers.size() > 0) {// 本地存在
                newUser.setRoleId(localUsers.get(0).getRoleId());
            } else {
                if (kateUser.getGroups().contains("CXL-ASRS-Admin")) {// 普通用户
                    newUser.setRoleId(1);
                } else if (kateUser.getGroups().contains("CXL-ASRS-User")) {
                    newUser.setRoleId(2);
                } else {
                    logger.error("当前用户不被允许登录：{}", newUser.getUserName());
                    rsp.setCode(ResponseCode.ERROR.getCode());
                    rsp.setMessage("当前用户不被允许登录");
                    return JSON.toJSONString(rsp);
                }
            }
            // 返回成功
            logger.info("登录成功，登录用户：{}", newUser.getUserName());
            rsp.setCode(ResponseCode.OK.getCode());
            rsp.setMessage("登录成功");
            // 返回用户数据
            rsp.setReturnData(generateUserInfo(BeanUtil.copyProperties(newUser, UserDto.class), HttpUtils.getIpAddr(servletRequest)));
        } catch (Exception exception) {
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            logger.error(exception.getMessage());
            // 返回其他异常
            rsp.setCode(ResponseCode.ERROR.getCode());
            rsp.setMessage("构建用户及菜单错误");
        }
        return JSON.toJSONString(rsp);
    }

    /**
     * 构造用户信息（菜单、按钮等权限）
     * @param currentUser 当前用户
     * @param ip ip地址
     * @return 用户信息
     */
    private UserConfigEntity generateUserInfo (UserDto currentUser, String ip) {
        UserConfigEntity userConfigEntity = new UserConfigEntity();
        try {
            if (currentUser.getRoleId() == null) {
                return null;
            }
            List<MenuDto> menus = menuService.selMenuByRoleId(currentUser.getRoleId());
            List<MenuEntity> menuList = new LinkedList<>();
            // 查找一级菜单
            for (MenuDto firstMenu : menus) {
                if (WmsConstants.ROOT_MENU_ID.equals(firstMenu.getParentId())) {// 查找到所有的一级子菜单
                    MenuEntity tempFirstMenu = new MenuEntity();
                    tempFirstMenu.setId(firstMenu.getMenuId());// ID
                    tempFirstMenu.setLabelName(firstMenu.getLabelName());// 菜单显示名称
                    tempFirstMenu.setIconValue(firstMenu.getIconValue());// 图标
                    tempFirstMenu.setPath(firstMenu.getPath());// 路径
                    // 设置子菜单
                    List<MenuEntity> tempFirstMenuChildren = new LinkedList<>();
                    for (MenuDto secondMenu : menus) {
                        if (firstMenu.getMenuId().equals(secondMenu.getParentId())) {
                            MenuEntity tempSecondMenu = new MenuEntity();
                            tempSecondMenu.setId(secondMenu.getMenuId());// ID
                            tempSecondMenu.setLabelName(secondMenu.getLabelName());// 菜单显示名称
                            tempSecondMenu.setIconValue(secondMenu.getIconValue());// 图标
                            tempSecondMenu.setPath(secondMenu.getPath());// 路径
                            // 设置子菜单
                            List<MenuEntity> tempSecondMenuChildren = new LinkedList<>();
                            for (MenuDto thirdMenu : menus) {
                                if (secondMenu.getMenuId().equals(thirdMenu.getParentId())) {
                                    MenuEntity tempThirdMenu = new MenuEntity();
                                    tempSecondMenu.setId(thirdMenu.getMenuId());// ID
                                    tempSecondMenu.setLabelName(thirdMenu.getLabelName());// 菜单显示名称
                                    tempSecondMenu.setIconValue(thirdMenu.getIconValue());// 图标
                                    tempSecondMenu.setPath(thirdMenu.getPath());// 路径
                                    // 添加按钮
                                    tempSecondMenuChildren.add(tempThirdMenu);
                                }
                            }
                            tempSecondMenu.setChildren(tempSecondMenuChildren);
                            // 添加二级菜单
                            tempFirstMenuChildren.add(tempSecondMenu);
                        }
                    }
                    tempFirstMenu.setChildren(tempFirstMenuChildren);
                    // 添加一级菜单
                    menuList.add(tempFirstMenu);
                }
            }
            logger.info("构造用户信息成功，当前用户：{}", currentUser.getUserName());
            // 设置返回信息
            userConfigEntity.setUser(BeanUtil.copyProperties(currentUser, UserDto.class));
            userConfigEntity.setMenuList(menuList);
            userConfigEntity.setStandId(standService.getStandIdByIp(ip));
        } catch (Exception e) {
            logger.error("构造用户信息失败，当前用户：{}", currentUser.getUserName());
        }
        return  userConfigEntity;
    }
}
