package cn.iocoder.yudao.module.system.controller.admin.auth;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.permission.dto.RoleReqDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
import cn.iocoder.yudao.module.system.controller.admin.user.LoginBody;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.service.ServicePackageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
import cn.iocoder.yudao.module.system.service.permission.MenuService;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.service.ServicePackageService;
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
import cn.iocoder.yudao.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.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.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;
    @Resource
    private PermissionApi permissionApi;
    @Resource
    private RoleApi roleApi;
    @Resource
    private ServicePackageService servicePackageService;


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


    /**
     * 登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/loginApp")
    public CommonResult loginApp(@RequestBody LoginBody loginBody) throws Exception {
        String userName = loginBody.getUsername();
        AdminUserDO user = userService.getUserByUsername(userName);
        if (ObjectUtil.isEmpty(user)) {
            return error(new ErrorCode(2_002_000_005, "登录账号不存在"));
        }
        // 获取登录用户的角色信息
        List<Long> roleIdsByUserId = permissionApi.getRoleIdsByUserId(user.getId());
        if (ObjectUtil.isEmpty(roleIdsByUserId) || roleIdsByUserId.size() == 0) {
            return error(new ErrorCode(2_002_000_005, "登录账号不存在"));
        }
        List<RoleReqDTO> roleList = roleApi.getRoleList();
        List<String> roleNames = roleList.stream().filter(item -> roleIdsByUserId.contains(item.getId())).map(item -> item.getName()).collect(Collectors.toList());
        if (roleList.isEmpty()){
            return error(new ErrorCode(2_002_000_005, "登录失败，当前登录用户未分配任何角色"));
        }
        if (loginBody.getTypes().equals("3") && !roleNames.contains("教练")){
            return error(new ErrorCode(2_002_000_005, "当前登录用户未分配教练角色"));
        }
        if (loginBody.getTypes().equals("2") && !roleNames.contains("驾校管理员")){
            return error(new ErrorCode(2_002_000_005, "当前登录用户未分配驾校管理员角色"));
        }

        AuthLoginReqVO authLoginReqVO = new AuthLoginReqVO();
        authLoginReqVO.setUsername(loginBody.getUsername());
        authLoginReqVO.setPassword(loginBody.getPassword());
        return success(authService.login(authLoginReqVO));
    }
    @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("/wxLoginJc")
//    public AjaxResult wxLoginJc(@RequestBody WxLoginBody wxLoginBody) {
//        String code = wxLoginBody.getCode();
//        //秘钥
//        String encryptedIv = wxLoginBody.getEncryptedIv();
//        //加密数据
//        String encryptedData = wxLoginBody.getEncryptedData();
//
//        //想微信服务器发送请求获取用户信息
//        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + wxConfig.getAppId() + "&secret=" + wxConfig.getAppSecret() + "&js_code=" + code + "&grant_type=authorization_code";
//        System.out.println(url);
//        String res = restTemplate.getForObject(url, String.class);
//        JSONObject jsonObject = JSONObject.parseObject(res);
//
//        //获取session_key和openid
//        String sessionKey = jsonObject.getString("session_key");
//        String openId = jsonObject.getString("openid");
//
//        System.out.println(sessionKey);
//        System.out.println(openId);
//        //解密
//        String decryptResult = "";
//        try {
//            //如果没有绑定微信开放平台，解析结果是没有unionid的。
//            decryptResult = decrypt(sessionKey, encryptedIv, encryptedData);
//        } catch (Exception e) {
//            e.printStackTrace();
//            return AjaxResult.error("微信登录失败！");
//        }
//
//        if (StringUtils.hasText(decryptResult)) {
//            //如果解析成功,获取token
//            String token = loginService.wxLoginJc(decryptResult,openId,wxLoginBody.getInviteId());
//            AjaxResult ajax = AjaxResult.success();
//            ajax.put(Constants.TOKEN, token);
//            return ajax;
//        } else {
//            return AjaxResult.error("微信登录失败！");
//        }
//    }


    @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(String routeCode) {
        // 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));
        //过滤出来当前服务的菜单
        if (StringUtils.isNotEmpty(routeCode)){
            ServicePackageDO servicePackage = servicePackageService.getServicePackage(routeCode);
            Set<Long> servicePackageMenuIds = servicePackage.getMenuIds();
            menuIds=   menuIds.stream().filter(servicePackageMenuIds::contains).collect(Collectors.toSet());
        }
        List<MenuDO> menuList = menuService.getMenuList(menuIds);
        menuList = menuService.filterDisableMenus(menuList);

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

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

    @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);
    }

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

    @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));
    }

}
