package org.agt.module.system.controller.admin.auth;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
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.agt.framework.common.enums.CommonStatusEnum;
import org.agt.framework.common.enums.UserTypeEnum;
import org.agt.framework.common.pojo.CommonResult;
import org.agt.framework.security.config.SecurityProperties;
import org.agt.framework.security.core.util.SecurityFrameworkUtils;
import org.agt.module.system.controller.admin.auth.vo.AuthLoginReqVO;
import org.agt.module.system.controller.admin.auth.vo.AuthLoginRespVO;
import org.agt.module.system.controller.admin.auth.vo.AuthPermissionInfoRespVO;
import org.agt.module.system.controller.admin.auth.vo.AuthRegisterReqVO;
import org.agt.module.system.controller.admin.auth.vo.AuthResetPasswordByNameReqVO;
import org.agt.module.system.controller.admin.auth.vo.AuthSmsLoginReqVO;
import org.agt.module.system.controller.admin.auth.vo.AuthSmsSendReqVO;
import org.agt.module.system.controller.admin.auth.vo.AuthSocialLoginReqVO;
import org.agt.module.system.convert.auth.AuthConvert;
import org.agt.module.system.dal.dataobject.permission.MenuDO;
import org.agt.module.system.dal.dataobject.permission.RoleDO;
import org.agt.module.system.dal.dataobject.user.AdminUserDO;
import org.agt.module.system.enums.logger.LoginLogTypeEnum;
import org.agt.module.system.service.auth.AdminAuthService;
import org.agt.module.system.service.permission.MenuService;
import org.agt.module.system.service.permission.PermissionService;
import org.agt.module.system.service.permission.RoleService;
import org.agt.module.system.service.social.SocialClientService;
import org.agt.module.system.service.user.AdminUserService;
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.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.agt.framework.common.pojo.CommonResult.success;
import static org.agt.framework.common.util.collection.CollectionUtils.convertSet;
import static org.agt.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 SocialClientService socialClientService;

    @Resource
    private SecurityProperties securityProperties;

    @PostMapping("/login")
    @PermitAll
    @Operation(summary = "使用账号密码登录")
    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-permission-info")
    @Operation(summary = "获取登录用户的权限信息")
    public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
        // 1.1 获得用户信息
        AdminUserDO user = userService.getUser(getLoginUserId());
        if (user == null) {
            return success(null);
        }

        // 1.2 获得角色列表
        Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
        if (CollUtil.isEmpty(roleIds)) {
            return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
        }
        List<RoleDO> roles = roleService.getRoleList(roleIds);
        roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色

        // 1.3 获得菜单列表
        Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));

        Integer[] filterMenuIds = {1138, 1139, 1140, 1141, 1142, 1143, 1224, 1225, 1226, 1227, 1228, 1229, 5010, 108, 500, 501, 1040, 1042, 1043, 1045, 107, 1036, 1037, 1038, 1039, 1093, 1094, 1095, 1096, 1097, 1098, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, 2739, 109, 1046, 1048, 1261, 1263, 1264, 1265, 1266, 1267, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2083, 2, 106, 110, 114, 115, 116, 1031, 1032, 1033, 1034, 1035, 1050, 1051, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1060, 1070, 1075, 1083, 1084, 1085, 1086, 1087, 1089, 1243, 1255, 1256, 1257, 1258, 1259, 1260, 2472, 2478, 2479, 2480, 2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488, 2489, 2490, 2491, 2492, 2493, 2494, 2495, 2497, 2525, 2740,1237,1238,1239,1240,1241,1242,111,1078,1082,1088,113,1066,1067,112,1077,1090,1091,1092};
        if (user.getId() != 2) {
            menuIds = menuIds.stream().filter(item -> Arrays.stream(filterMenuIds).noneMatch(m -> Objects.equals(Long.valueOf(m), item))
            ).collect(Collectors.toSet());
        }

        List<MenuDO> menuList = menuService.getMenuList(menuIds);
        menuList = menuService.filterDisableMenus(menuList);

        // 2. 拼接结果返回
        return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
    }

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

    // ========== 短信登录相关 ==========

    @PostMapping("/sms-login")
    @PermitAll
    @Operation(summary = "使用短信验证码登录")
    public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
        return success(authService.smsLogin(reqVO));
    }

    @PostMapping("/send-sms-code")
    @PermitAll
    @Operation(summary = "发送手机验证码")
    public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
        authService.sendSmsCode(reqVO);
        return success(true);
    }

    @PostMapping("/reset-password")
    @PermitAll
    @Operation(summary = "重置密码")
    public CommonResult<Boolean> resetPassword(@RequestBody @Valid AuthResetPasswordByNameReqVO reqVO) {
        authService.resetPasswordByName(reqVO);
        return success(true);
    }

    // ========== 社交登录相关 ==========

    @GetMapping("/social-auth-redirect")
    @PermitAll
    @Operation(summary = "社交授权的跳转")
    @Parameters({
            @Parameter(name = "type", description = "社交类型", required = true),
            @Parameter(name = "redirectUri", description = "回调路径")
    })
    public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
                                            @RequestParam("redirectUri") String redirectUri) {
        return success(socialClientService.getAuthorizeUrl(
                type, UserTypeEnum.ADMIN.getValue(), redirectUri));
    }

    @PostMapping("/social-login")
    @PermitAll
    @Operation(summary = "社交快捷登录，使用 code 授权码", description = "适合未登录的用户，但是社交账号已绑定用户")
    public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
        return success(authService.socialLogin(reqVO));
    }

}
