package com.njcn.msgpush.module.system.controller.admin.auth;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.njcn.msgpush.framework.common.enums.CommonStatusEnum;
import com.njcn.msgpush.framework.common.pojo.CommonResult;
import com.njcn.msgpush.framework.encrypt.core.annotation.ApiEncrypt;
import com.njcn.msgpush.framework.security.config.SecurityProperties;
import com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthLoginReqVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthRegisterReqVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthUserRouteRespVO;
import com.njcn.msgpush.module.system.controller.admin.auth.vo.AuthUserInfoRespVO;
import com.njcn.msgpush.module.system.convert.auth.AuthConvert;
import com.njcn.msgpush.module.system.dal.dataobject.permission.MenuDO;
import com.njcn.msgpush.module.system.dal.dataobject.permission.RoleDO;
import com.njcn.msgpush.module.system.dal.dataobject.user.AdminUserDO;
import com.njcn.msgpush.module.system.enums.logger.LoginLogTypeEnum;
import com.njcn.msgpush.module.system.service.auth.AdminAuthService;
import com.njcn.msgpush.module.system.service.permission.MenuService;
import com.njcn.msgpush.module.system.service.permission.PermissionService;
import com.njcn.msgpush.module.system.service.permission.RoleService;
import com.njcn.msgpush.module.system.service.user.AdminUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.Set;

import static com.njcn.msgpush.framework.common.pojo.CommonResult.success;
import static com.njcn.msgpush.framework.common.util.collection.CollectionUtils.convertSet;
import static com.njcn.msgpush.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;

@Tag(name = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth")
@Validated
@Slf4j
public class AuthController {

    @Resource
    private AdminAuthService authService;
    @Resource
    private AdminUserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private MenuService menuService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private SecurityProperties securityProperties;

    @PostMapping("/login")
    @PermitAll
    @Operation(summary = "使用账号密码登录")
    @ApiEncrypt(response = false, requestFields = {"password"})
    public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
        return success(authService.login(reqVO));
    }

    @PostMapping("/logout")
    @PermitAll
    @Operation(summary = "登出系统")
    public CommonResult<Boolean> logout(HttpServletRequest request) {
        String token = SecurityFrameworkUtils.obtainAuthorization(request,
                securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
        if (StrUtil.isNotBlank(token)) {
            authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
        }
        return success(true);
    }

    @PostMapping("/refresh-token")
    @PermitAll
    @Operation(summary = "刷新令牌")
    @Parameter(name = "refreshToken", description = "刷新令牌", required = true)
    public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
        return success(authService.refreshToken(refreshToken));
    }

    @GetMapping("/get-user-info")
    @Operation(summary = "获取登录用户信息")
    public CommonResult<AuthUserInfoRespVO> getUserInfo() {
        // 1.1 获得用户信息
        AdminUserDO user = userService.getUser(getLoginUserId());
        if (user == null) {
            return success(null);
        }

        // 1.2 获得角色和按钮权限
        List<RoleDO> roles = getCurrentUserRoles();
        List<MenuDO> menuList = getCurrentUserMenus(roles);
        return success(AuthConvert.INSTANCE.convertUserInfo(user, roles, menuList));
    }

    @GetMapping("/get-user-routes")
    @Operation(summary = "获取登录用户路由信息")
    public CommonResult<AuthUserRouteRespVO> getUserRoutes() {
        AdminUserDO user = userService.getUser(getLoginUserId());
        if (user == null) {
            return success(null);
        }

        List<RoleDO> roles = getCurrentUserRoles();
        List<MenuDO> menuList = getCurrentUserMenus(roles);
        return success(AuthConvert.INSTANCE.convertUserRoutes(menuList));
    }

    @GetMapping("/get-permission-info")
    @Operation(summary = "获取登录用户的权限信息")
    public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
        AdminUserDO user = userService.getUser(getLoginUserId());
        if (user == null) {
            return success(null);
        }

        List<RoleDO> roles = getCurrentUserRoles();
        if (CollUtil.isEmpty(roles)) {
            return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
        }

        List<MenuDO> menuList = getCurrentUserMenus(roles);
        return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
    }

    @PostMapping("/register")
    @PermitAll
    @Operation(summary = "注册用户")
    @ApiEncrypt(response = false, requestFields = {"password"})
    public CommonResult<AuthLoginRespVO> register(@RequestBody @Valid AuthRegisterReqVO registerReqVO) {
        return success(authService.register(registerReqVO));
    }

    private List<RoleDO> getCurrentUserRoles() {
        Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
        if (CollUtil.isEmpty(roleIds)) {
            return Collections.emptyList();
        }

        List<RoleDO> roles = roleService.getRoleList(roleIds);
        roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus()));
        return roles;
    }

    private List<MenuDO> getCurrentUserMenus(List<RoleDO> roles) {
        if (CollUtil.isEmpty(roles)) {
            return Collections.emptyList();
        }

        Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
        List<MenuDO> menuList = menuService.getMenuList(menuIds);
        return menuService.filterDisableMenus(menuList);
    }

}
