package com.gci.boot.modules.system.controller;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gci.boot.common.log.annotation.AddSysLog;
import com.gci.boot.common.util.JsonUtil;
import com.gci.boot.common.util.ParamsCheckUtil;
import com.gci.boot.common.util.QueryWrapperUtil;
import com.gci.boot.common.vo.Result;
import com.gci.boot.exception.GciBootException;
import com.gci.boot.modules.projects.entity.ProjectUserRel;
import com.gci.boot.modules.projects.service.IProjectUserRelService;
import com.gci.boot.modules.projects.service.IProjectsService;
import com.gci.boot.modules.system.entity.*;
import com.gci.boot.modules.system.service.ISysDepartService;
import com.gci.boot.modules.system.service.ISysUserDepartService;
import com.gci.boot.modules.system.service.ISysUserRoleService;
import com.gci.boot.modules.system.service.ISysUserService;
import com.gci.boot.modules.system.util.AesEncryptUtil;
import com.gci.boot.modules.system.util.PasswordUtil;
import com.gci.boot.modules.system.util.QsEncodeUtil;
import com.gci.boot.modules.system.vo.LoginUser;
import com.gci.boot.properties.GciSecurityProperties;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author chenzhiwei
 * @since 2023-08-18
 */
@EnableConfigurationProperties(GciSecurityProperties.class)
@RestController
@RequestMapping("/sys/user")
@Slf4j
public class SysUserController {
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysUserRoleService sysUserRoleService;
    @Autowired
    private ISysUserDepartService sysUserDepartService;
    @Autowired
    private GciSecurityProperties gciSecurityProperties;
    @Autowired
    private ISysDepartService sysDepartService;
    @Autowired
    private IProjectsService projectsService;
    @Autowired
    private IProjectUserRelService projectUserRelService;

    /**
     * 获取用户列表数据
     *
     * @param user
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AddSysLog("查询用户列表")
    @GetMapping("/list")
    public Result<IPage<SysUser>> queryPageList(SysUser user, String column, String order, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
        Result<IPage<SysUser>> result = new Result<>();
        if(StringUtils.isBlank(column)){
            column = "create_time";
            order = "desc";
        }
        QueryWrapper<SysUser> queryWrapper = QueryWrapperUtil.builder()
                .table(SysUser.class)
                .like(SysUser::getUsername)
                .like(SysUser::getRealname)
                .like(SysUser::getPhone)
                .like(SysUser::getEmail)
                .like(SysUser::getTelephone)
                .orderColums(column)
                .orders(order)
                .buildFromObject(user);

        Page<SysUser> page = new Page<>(pageNo, pageSize);
        IPage<SysUser> pageList = sysUserService.page(page, queryWrapper);

        // 处理等保解密数据
        Iterator<SysUser> userIterator = pageList.getRecords().iterator();
        while (userIterator.hasNext()) {
            SysUser sysUser = userIterator.next();
            sysUser.setPhone(sysUserService.processPhone(sysUser));
        }

        result.setSuccess(true);
        result.setResult(pageList);
        log.info(pageList.toString());
        return result;
    }


    /**
     * 查询用户信息 单独列表使用 需要联表查询
     * @param user
     * @param column
     * @param order
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @AddSysLog("查询用户列表")
    @GetMapping("/listV2")
    public Result<?> queryPageListV2(SysUser user, String column, String order, String roleName, String departName, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
        if(StringUtils.isBlank(column)){
            column = "create_time";
            order = "desc";
        }
        Page<SysUser> page = new Page<>(pageNo, pageSize);
        IPage<SysUser> iPage = sysUserService.queryPageListV2(user,roleName,departName,column,order,page);
        return Result.ok(iPage);
    }


    @AddSysLog("添加用户")
    @PostMapping("/add")
    public Result<SysUser> add(@RequestBody Map<String, Object> map) {
        String roles = (String) map.get("selectedroles");
        String departs = (String) map.get("selecteddeparts");

        SysUser user = JsonUtil.map2Object(map, SysUser.class);
        ParamsCheckUtil.paramsAssert().notBlank(user.getUsername(), "【用户名】不能为空！")
                .notBlank(user.getPassword(), "【密码】不能为空！")
                .isTrue(sysUserService.lambdaQuery().eq(SysUser::getUsername, user.getUsername()).count() == 0, String.format("用户名【%s】已存在！", user.getUsername()))
                .isTrue(PasswordUtil.checkPassword(user.getPassword()), "密码必须由8-12位数字、大小写字母和特殊符号组成")
        ;

        user.setCreateTime(new Date());//设置创建时间
        String salt = PasswordUtil.generateSalt(8);
        user.setSalt(salt);
        String passwordEncode = PasswordUtil.encrypt(user.getUsername(), user.getPassword(), salt);
        user.setPassword(passwordEncode);
        user.setStatus(1);
        if (StringUtils.isNotBlank(user.getPhone())) {
            // 是否开启密码加密存储，如按等保要求，密码需要加密存储
            if (gciSecurityProperties.isEnablePhoneEncrypt()) {
                String secret = PasswordUtil.generateSalt(8);
                try {
                    user.setEncryptPhone(QsEncodeUtil.aesEncrypt(user.getPhone(), secret));
                } catch (Exception e) {
                    return Result.error("【电话号码】加密失败！");
                }
                user.setSecretPhone(secret);
                user.setPhone("");
            } else {
                user.setEncryptPhone("");
                user.setSecretPhone("");
            }
        }
        List<String> rolesList = Optional.ofNullable(roles).filter(StringUtils::isNotBlank).map(r -> r.split(",")).map(Arrays::asList).orElse(new ArrayList<>());
        List<String> departsList = Optional.ofNullable(departs).filter(StringUtils::isNotBlank).map(r -> r.split(",")).map(Arrays::asList).orElse(new ArrayList<>());
        String projs = (String) map.get("projectIds");
        List<String> projsList = Optional.ofNullable(projs).map(r -> r.split(",")).map(Arrays::asList)
                .map(list -> list.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList()))
                .orElse(new ArrayList<>());
        sysUserService.addInnerUser(user, rolesList, departsList,projsList);
        return Result.ok("添加成功！");
    }

    @AddSysLog("编辑用户")
    @PutMapping("/edit")
    public Result<SysUser> edit(@RequestBody Map<String, Object> map) {
        SysUser sysUser = sysUserService.getById((String) map.get("id"));
        if (sysUser == null) {
            return Result.error("未找到对应实体");
        } else {
            SysUser user = JsonUtil.map2Object(map, SysUser.class);
            //不可修改密码
            user.setPassword(sysUser.getPassword());

            ParamsCheckUtil.ParamsAssert paramAssert = ParamsCheckUtil.paramsAssert().notBlank(user.getUsername(), "【用户名】不能为空！")
                    .isTrue(user.getUsername().equals(sysUser.getUsername()) || sysUserService.lambdaQuery().eq(SysUser::getUsername, user.getUsername()).count() == 0, String.format("用户名【%s】已存在！", user.getUsername()));

            if (StringUtils.isNotBlank(user.getPhone())) {
                // 是否开启密码加密存储，如按等保要求，密码需要加密存储
                if (gciSecurityProperties.isEnablePhoneEncrypt()) {
                    String secret = PasswordUtil.generateSalt(8);
                    try {
                        user.setEncryptPhone(QsEncodeUtil.aesEncrypt(user.getPhone(), secret));
                    } catch (Exception e) {
                        return Result.error("【电话号码】加密失败！");
                    }
                    user.setPhone("");
                } else {
                    user.setEncryptPhone("");
                    user.setSecretPhone("");
                }
            }
            String roles = (String) map.get("selectedroles");
            List<String> rolesList = Optional.ofNullable(roles).map(r -> r.split(",")).map(Arrays::asList)
                    .map(list -> list.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList()))
                    .orElse(new ArrayList<>());
            String departs = (String) map.get("selecteddeparts");
            List<String> departsList = Optional.ofNullable(departs).map(r -> r.split(",")).map(Arrays::asList)
                    .map(list -> list.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList()))
                    .orElse(new ArrayList<>());
            String projs = (String) map.get("projectIds");
            List<String> projsList = Optional.ofNullable(projs).map(r -> r.split(",")).map(Arrays::asList)
                    .map(list -> list.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList()))
                    .orElse(new ArrayList<>());
            //编辑内部用户（包括关联项目），兼容其他类型的用户修改
            sysUserService.editInnerUser(user, rolesList, departsList,projsList);
            return Result.ok("修改成功!");
        }
    }


    /**
     * 冻结&解冻用户
     *
     * @param map
     * @return
     */
    @AddSysLog("冻结/解冻用户")
    @PostMapping("/frozenBatch")
    public Result<SysUser> frozenBatch(@RequestBody Map<String, String> map) {
        String status = map.get("status");
        List<String> userIdList = Optional.ofNullable(map.get("ids")).map(r -> r.split(",")).map(Arrays::asList).orElse(new ArrayList<>());
        sysUserService.lambdaUpdate().in(SysUser::getId, userIdList).set(SysUser::getStatus, Integer.parseInt(status)).update();
        return Result.ok("操作成功!");
    }

    @ApiOperation("获取个人信息接口")
    @GetMapping("/queryById")
    public Result<SysUser> queryById(String id) {
        SysUser sysUser = sysUserService.getById(id);
        if (sysUser == null) {
            return Result.error("未找到对应实体");
        }
        return Result.ok(sysUser);
    }

    /**
     * 批量删除用户
     */
    @AddSysLog("删除用户")
    @DeleteMapping("/deleteBatch")
    public Result<?> deleteBatch(String ids) {
        this.sysUserService.deleteBatch(Arrays.asList(ids.split(",")));
        return Result.ok("删除用户成功");
    }

    @GetMapping("/getUserInfoByToken")
    public Result<?> getUserInfoByToken() {
        LoginUser user = (LoginUser)SecurityUtils.getSubject().getPrincipal();
        Set<String> userRolesSet = sysUserService.getUserRolesSet(user.getUsername());
        if(userRolesSet.size()>0){
            user.setRoles(userRolesSet.stream().collect(Collectors.joining(",")));
        }
        return Result.ok(user);
    }

    /**
     * 用户重置自己的密码
     */
    @AddSysLog("个人重置密码")
    @PutMapping("/updatePassword")
    public Result<?> changPassword(@RequestBody Map<String, String> params) {
        String username = params.get("username");
        String oldPassword = params.get("oldPassword");
        String password = params.get("password");
        String confirmPassword = params.get("confirmPassword");
        SysUser user = this.sysUserService.getByUsername(username);
        if (user == null) {
            return Result.error("用户不存在！");
        }
        sysUserService.resetPassword(username, oldPassword, password, confirmPassword);
        return Result.ok("密码重置成功!");
    }

    /**
     * 修改密码接口
     */
    @AddSysLog("用户管理-修改密码")
    @PutMapping("/changePassword")
    public Result<?> changePassword(@RequestBody SysUser sysUser) {
        SysUser u = sysUserService.getByUsername(sysUser.getUsername());
        if (u == null) {
            return Result.error("用户不存在！");
        }
        try {
            sysUser.setPassword(AesEncryptUtil.desEncrypt(sysUser.getPassword().replaceAll("%2B", "\\+")).trim());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("修改密码解密失败",e);
            throw new GciBootException("修改密码失败！");
        }
        String salt = PasswordUtil.generateSalt(8);
        if(!PasswordUtil.checkPassword(sysUser.getPassword())){
            return Result.error("密码必须由8-12位数字、大小写字母和特殊符号组成！");
        }
        String passwordEncode = PasswordUtil.encrypt(sysUser.getUsername(), sysUser.getPassword(), salt);
        sysUserService.lambdaUpdate()
                .eq(SysUser::getId, u.getId())
                .set(SysUser::getPasswordUpdateTime, new Date())
                .set(SysUser::getPassword, passwordEncode)
                .set(SysUser::getSalt, salt)
                .update();
        return Result.ok("修改密码成功！");
    }

    @GetMapping("/queryUserRole")
    public Result<List<String>> queryUserRole(String userid) {
        List<String> list = new ArrayList<>();
        List<SysUserRole> userRole = sysUserRoleService.lambdaQuery().eq(SysUserRole::getUserId, userid).list();
        for (SysUserRole sysUserRole : userRole) {
            list.add(sysUserRole.getRoleId());
        }
        return Result.ok(list);
    }

    @GetMapping("/queryUserDepart")
    public Result<List<String>> queryUserDepart(String userId) {
        List<String> list = new ArrayList<>();
        List<SysUserDepart> userDeparts = sysUserDepartService.lambdaQuery().eq(SysUserDepart::getUserId, userId).list();
        for (SysUserDepart sysUserDepart : userDeparts) {
            list.add(sysUserDepart.getDepId());
        }
        return Result.ok(list);
    }

    @GetMapping("/queryUserProject")
    public Result<?> queryUserProject(String userId){
        InnerUserProject userProject = new InnerUserProject();
        //查询是否是内部用户
        List<SysDepart> listDepart = sysDepartService.getDepartByUserId(userId);
        userProject.setOrgCategory(0);
        for(SysDepart dep: listDepart){
            if(dep.getOrgCategory() == 1){
                userProject.setOrgCategory(1);
                break;
            }else{
                if(dep.getOrgCategory() == 3 || dep.getOrgCategory() == 2){
                    userProject.setOrgCategory(dep.getOrgCategory());
                }
            }
        }
        if(userProject.getOrgCategory()==1){
            QueryWrapper<ProjectUserRel> queryWrapperProj = new QueryWrapper<>();
            queryWrapperProj.eq("user_id",userId);
            //查询内部用户归属的项目
            List<ProjectUserRel> listProjOfUser = projectUserRelService.list(queryWrapperProj);
            String projIds = null;
            for (ProjectUserRel projectUserRel : listProjOfUser) {
                if(projIds==null) {
                    projIds = projectUserRel.getProjectId();
                }else {
                    projIds += ","+projectUserRel.getProjectId();
                }
            }
            userProject.setProjectIds(projIds);
        }
        return Result.ok(userProject);
    }

    @GetMapping("/getByRoleCode")
    public Result<?> getByRoleCode(String roleCode) {
        return Result.ok(sysUserService.getByRoleCode(roleCode));
    }


    @ApiOperation("解绑微信用户")
    @AddSysLog(value = "用户管理-解绑微信用户")
	@GetMapping("/unbindUser")
    public Result<SysUser> unbindUser(String id) {
        SysUser sysUser = sysUserService.getById(id);
        if (sysUser == null) {
            return Result.error("未找到对应用户");
        }
        sysUser.setOpenid(null);
        sysUserService.updateById(sysUser);
        return Result.ok("解绑成功！");
    }

    @AddSysLog("查询内部用户列表")
    @GetMapping("/innerUserList")
    public Result<IPage<SysUser>> queryInnerUserPageList(SysUser user, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) {
        Result<IPage<SysUser>> result = new Result<>();

        //查询内部机构树
        Page<SysUser> page = new Page<>(pageNo, pageSize);
        IPage<SysUser> pageList = sysUserService.queryInnerUserList(page, user);

        // 处理等保解密数据
        Iterator<SysUser> userIterator = pageList.getRecords().iterator();
        while (userIterator.hasNext()) {
            SysUser sysUser = userIterator.next();
            sysUser.setPhone(sysUserService.processPhone(sysUser));
        }

        result.setSuccess(true);
        result.setResult(pageList);
        log.info(pageList.toString());
        return result;
    }

}
