package com.ssyf.module.auth.controller.auth;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.jcraft.jsch.UserInfo;
import com.ssyf.common.core.util.EntityUtil;
import com.ssyf.module.auth.domain.bo.UserRoleRelationBo;
import com.ssyf.module.auth.domain.entity.User;
import com.ssyf.module.auth.domain.query.*;
import com.ssyf.module.auth.domain.vo.UserInfoVo;
import com.ssyf.module.auth.service.*;
import com.ssyf.common.core.domain.query.KeysQuery;
import com.ssyf.common.security.aop.CertificateValid;
import com.ssyf.common.security.domain.ClientInfo;
import com.ssyf.common.security.helper.ClientContextHelper;
import com.ssyf.common.web.aop.RequestSynchronization;

import com.ssyf.plugs.mysql.helper.PageEnhanceHelper;
import com.ssyf.common.web.apicode.ApiCodeUser;
import com.ssyf.common.web.result.Result;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 
 * @author huwei
 * @date 2022/11/11 14:22
 */
@Api(tags="权限-用户接口")
@RestController
@RequestMapping("/auth/user")
public class UserAuthController {

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private MenuPermissionService menuPermissionService;

    //@SaCheckPermission(value = {"user:create" ,"user:add"} ,mode= SaMode.OR)
    @RequestSynchronization
    @ApiOperation(value = "创建用户")
    @PostMapping(value = "/create")
    public Result createUser(@Validated @RequestBody UserQuery query){
        if(BeanUtil.isEmpty(query)){
            return Result.fail(ApiCodeUser.PARAMETER_ERROR);
        }
        User user = this.userService.createUser(query);
        return Result.success(BeanUtil.copyProperties(user , UserInfoVo.class));
    }

    @RequestSynchronization
    @ApiOperation(value = "创建运营用户")
    @PostMapping(value = "/createYunying")
    public Result createYunying(@Validated @RequestBody UserQuery query){
        if(BeanUtil.isEmpty(query)){
            return Result.fail(ApiCodeUser.PARAMETER_ERROR);
        }
        User user = this.userService.createYunying(query);
        return Result.success(BeanUtil.copyProperties(user , UserInfoVo.class));
    }

    //@SaCheckPermission(value = {"user:update" ,"user:edit"} ,mode= SaMode.OR)
    @RequestSynchronization
    @ApiOperation(value = "更新用户的信息")
    @PostMapping(value = "/update/{userUid}")
    public Result updateByUid(@PathVariable String userUid ,@Validated @RequestBody UserQuery query){
        if(BeanUtil.isEmpty(query)){
            return Result.fail(ApiCodeUser.PARAMETER_ERROR.getCode() ,"更新数据不能为空");
        }
        this.userService.updateByUid(userUid ,query);
        return Result.success();
    }

    //@SaCheckPermission("user:markDelete")
    @RequestSynchronization
    @ApiOperation(value = "标记删除")
    @PostMapping(value = "/markDelete/{userUid}")
    public Result markDelete(@PathVariable String userUid){
        this.userService.markDelete(userUid);
        return Result.success();
    }
    //@SaCheckPermission("user:delete")
    @RequestSynchronization
    @ApiOperation(value = "删除用户")
    @PostMapping(value = "/removeByUid/{userUid}")
    public Result remove(@PathVariable String userUid){
        this.userService.removeByUid(userUid);
        return Result.success();
    }

    //@SaCheckPermission("user:query")
    @ApiOperation(value = "分页获取用户数据")
    @PostMapping(value = "/queryPage")
    public Result queryPage(@Validated @RequestBody UserPageQuery query){
        PageInfo<User> pageInfo = this.userService.getPage(query);

        if(CollectionUtil.isNotEmpty(pageInfo.getList())){
            Map<String ,UserInfoVo> userUidToUserInfoVo = new HashMap<>();
            List<UserInfoVo> userInfos = new ArrayList<>();
            List<String> userUids = new ArrayList<>();
            for(User user : pageInfo.getList()){
                UserInfoVo userInfoVo = BeanUtil.copyProperties(user , UserInfoVo.class);
                userUids.add(user.getUid());
                userInfos.add(userInfoVo);
                userUidToUserInfoVo.put(user.getUid(),userInfoVo);
            }
            List<UserRoleRelationBo> bos = this.roleService.getBoByUserUids(userUids);
            for(UserRoleRelationBo bo : bos){
                UserInfoVo userInfoVo = userUidToUserInfoVo.get(bo.getUserUid());
                if(userInfoVo != null){
                    userInfoVo.getRoles().add(bo.getRoleName());
                }
            }
            PageInfo<UserInfoVo> pageInfoVo = new PageInfo<>(userInfos);
            pageInfoVo.setTotal(pageInfo.getTotal());
            pageInfoVo.setPageNum(pageInfo.getPageNum());
            pageInfoVo.setPageSize(pageInfo.getPageSize());
            pageInfoVo.setSize(pageInfo.getSize());
            return Result.success(pageInfoVo);
        }

        return Result.success(PageEnhanceHelper.switchPageInfo(pageInfo , UserInfoVo.class));
    }

    @ApiOperation(value = "获取用户数据（所有）")
    @PostMapping(value = "/queryList")
    public Result queryList(@Validated @RequestBody UserPageQuery query){
        List<User> list = this.userService.getList(query);
        return Result.success(EntityUtil.copyProperties(list , UserInfoVo.class));
    }



    //@SaCheckPermission("user:authAnd")
    @RequestSynchronization
    @ApiOperation(value = "判断用户是否具有相关权限")
    @PostMapping(value = "/authAnd/{userUid}")
    public Result authAndByUserUid(@PathVariable String userUid ,@Validated @RequestBody KeysQuery<String> query){
        if(CollectionUtil.isEmpty(query.getList())){
            return Result.fail(ApiCodeUser.PARAMETER_ERROR);
        }
        boolean b = this.userService.authAnd(userUid,query.getList());
        return Result.success(b);
    }

    //@SaCheckPermission("user:authOr")
    @RequestSynchronization
    @ApiOperation(value = "判断用户是否具有相关权限之一")
    @PostMapping(value = "/authOr/{userUid}")
    public Result authOrByUserUid(@PathVariable String userUid ,@Validated @RequestBody KeysQuery<String> query){
        if(CollectionUtil.isEmpty(query.getList())){
            return Result.fail(ApiCodeUser.PARAMETER_ERROR);
        }
        boolean b = this.userService.authOr(userUid,query.getList());
        return Result.success(b);
    }

    //@SaCheckPermission("user:authAnd")
    @RequestSynchronization
    @ApiOperation(value = "判断用户是否具有相关权限")
    @PostMapping(value = "/authAnd")
    public Result authAnd(@Validated @RequestBody KeysQuery<String> query){
        if(CollectionUtil.isEmpty(query.getList())){
            return Result.fail(ApiCodeUser.PARAMETER_ERROR);
        }
        boolean b = this.userService.authAnd(ClientContextHelper.getClientInfo().getId().toString(),query.getList());
        return Result.success(b);
    }

    //@SaCheckPermission("user:authOr")
    @RequestSynchronization
    @ApiOperation(value = "判断用户是否具有相关权限之一")
    @PostMapping(value = "/authOr")
    public Result authOr(@Validated @RequestBody KeysQuery<String> query){
        if(CollectionUtil.isEmpty(query.getList())){
            return Result.fail(ApiCodeUser.PARAMETER_ERROR);
        }
        boolean b = this.userService.authOr(ClientContextHelper.getClientInfo().getId().toString(),query.getList());
        return Result.success(b);
    }

    //@SaCheckPermission("user:assignRole")
    @RequestSynchronization
    @ApiOperation(value = "分配指定角色的权限")
    @PostMapping(value = "/assignOrRemoveRole")
    public Result assignOrRemoveRole(@Validated @RequestBody AssignQuery query) {
        if(BeanUtil.isEmpty(query)){
            return Result.fail(ApiCodeUser.PARAMETER_ERROR);
        }
        this.userService.assignOrRemoveRole(query.getId() ,query.getAssignIds());
        return Result.success();
    }

    @ApiOperation(value = "刷新token")
    @PostMapping(value = "/refresh/token")
    public Result refreshToken(){
        StpUtil.updateLastActiveToNow();
        return Result.success(StpUtil.getTokenValue());
    }

    /**
     *
     * @param getRoles
     * @param getMenus
     * @return
     */
    @RequestSynchronization
    @ApiOperation(value = "查询当前用户的信息")
    @PostMapping(value = "/query/current")
    public Result<UserInfoVo> queryCurrent(@RequestParam(required = false ,defaultValue = "false") Boolean getRoles ,@RequestParam(required = false ,defaultValue = "false") Boolean getMenus){
        ClientInfo clientInfo = ClientContextHelper.getClientInfo();
        User user = this.userService.getOneByUid(clientInfo.getId().toString());
        //脱敏
        user = this.userService.desensitize(user);
        UserInfoVo userInfoVo = BeanUtil.copyProperties(user , UserInfoVo.class);
        //角色
        if(getRoles){
            userInfoVo.setRoles(this.roleService.getVisibleNamesByUserUid(user.getUid() ,null));
        }
        //菜单
        if(getMenus){
            userInfoVo.setMenus(this.menuPermissionService.getVisibleMenusByUserUid(user.getUid() ,null));
        }
        return Result.success(userInfoVo);
    }

    @RequestSynchronization
    @ApiOperation(value = "更新当前用户信息")
    @PostMapping(value = "/updateNickname")
    public Result update(@RequestParam String nickname){
        ClientInfo clientInfo = ClientContextHelper.getClientInfo();
        this.userService.updateByUid(clientInfo.getId().toString() ,new UserQuery().setNickname(nickname));
        return Result.success();
    }

    /**
     * 调用该接口用户需前置获取更新校验
     * 本接口使用用户的动态secret进行md5加密校验，所以在使用该接口前使用动态secret生成校验码即可
     * @param query
     * @return
     */
//    @CertificateValid(type = "captchaSms" ,contentVar = "query.phone")
    @RequestSynchronization
    @ApiOperation(value = "更新当前用户的手机")
    @PostMapping(value = "/updatePhone")
    public Result updatePhone(@Validated @RequestBody UserQuery query){
        ClientInfo clientInfo = ClientContextHelper.getClientInfo();
        this.userService.updateByUid(clientInfo.getId().toString() ,new UserQuery().setPhone(query.getPhone()));
        return Result.success();
    }

    /**
     * 调用该接口用户需前置获取更新校验
     * 本接口使用用户的动态secret进行md5加密校验，所以在使用该接口前使用动态secret生成校验码即可
     * @param query
     * @return
     */
    @CertificateValid(type = "captchaMail" ,contentVar = "query.mail")
    @RequestSynchronization
    @ApiOperation(value = "更新当前用户的邮箱")
    @PostMapping(value = "/updateMail")
    public Result updateMail(@Validated @RequestBody UserQuery query){
        ClientInfo clientInfo = ClientContextHelper.getClientInfo();
        this.userService.updateByUid(clientInfo.getId().toString() ,new UserQuery().setMail(query.getMail()));
        return Result.success();
    }

    /**
     * 调用该接口用户需前置获取更新校验
     * 本接口使用用户的动态secret进行md5加密校验，所以在使用该接口前使用动态secret生成校验码即可
     * @return
     */
//    @CertificateValid
    @RequestSynchronization
    @ApiOperation(value = "注销用户")
    @PostMapping(value = "/cancel")
    public Result cancel(){
        ClientInfo clientInfo = ClientContextHelper.getClientInfo();
        this.userService.markDelete(clientInfo.getId().toString());
        return Result.success();
    }

    @ApiOperation(value = "登出")
    @PostMapping(value = "/logout")
    public Result logout(){
        StpUtil.logout();
        return Result.success();
    }
}
