package com.dsk.web.controller.system;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.dsk.biz.utils.ExcelUtils;
import com.dsk.common.annotation.Log;
import com.dsk.common.constant.GlobalConstants;
import com.dsk.common.constant.TenantConstants;
import com.dsk.common.core.controller.BaseController;
import com.dsk.common.core.domain.PageQuery;
import com.dsk.common.core.domain.R;
import com.dsk.common.core.page.TableDataInfo;
import com.dsk.common.enums.BusinessType;
import com.dsk.common.exception.ServiceException;
import com.dsk.common.helper.LoginHelper;
import com.dsk.common.tenant.helper.TenantHelper;
import com.dsk.common.utils.StreamUtils;
import com.dsk.common.utils.StringUtils;
import com.dsk.common.utils.poi.ExcelUtil;
import com.dsk.common.utils.redis.RedisUtils;
import com.dsk.system.domain.SysDept;
import com.dsk.system.domain.SysRole;
import com.dsk.system.domain.SysUser;
import com.dsk.system.domain.vo.SysUserExportVo;
import com.dsk.system.domain.vo.SysUserImportVo;
import com.dsk.system.domain.vo.SysUserVo;
import com.dsk.system.service.ISysDeptService;
import com.dsk.system.service.ISysPostService;
import com.dsk.system.service.ISysRoleService;
import com.dsk.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.util.*;

/**
 * 用户信息
 *
 * @author Lion Li
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController {

    private final ISysUserService userService;
    private final ISysRoleService roleService;
    private final ISysPostService postService;
    private final ISysDeptService deptService;

    /**
     * 根据租户ID查询大司空超管or租户管理员为其创建的企业管理员和管理员账号数量
     */
    @SaCheckRole(value = {TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.DSK_TENANT_ADMIN_ROLE_KEY}, mode = SaMode.OR)
    @SaCheckPermission(value = "system:user:query", orRole = "accountAdmin")
    @GetMapping("/queryTenantAdminNumCreatedByDSK/{tenantId}")
    public R<Long> queryTenantAdminNumCreatedByDSK(@NotNull(message = "租户ID不能为空") @PathVariable Long tenantId) {
        return R.ok(TenantHelper.ignore(() -> userService.queryTenantAdminNumCreatedByDSK(tenantId)));
    }

    /**
     * 获取用户列表
     */
    @SaCheckPermission("system:user:list")
    @GetMapping("/list")
    public TableDataInfo<SysUser> list(SysUser user, PageQuery pageQuery) {
        return userService.selectPageUserList(user, pageQuery);
    }

    /**
     * 导出用户列表
     */
    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:user:export")
    @PostMapping("/export")
    public void export(SysUser user, HttpServletResponse response) {
        List<SysUser> list = userService.selectUserList(user);
        List<SysUserExportVo> listVo = BeanUtil.copyToList(list, SysUserExportVo.class);
        for (int i = 0; i < list.size(); i++) {
            SysDept dept = list.get(i).getDept();
            SysUserExportVo vo = listVo.get(i);
            if (ObjectUtil.isNotEmpty(dept)) {
                vo.setDeptName(dept.getDeptName());
                //vo.setLeader(dept.getLeader());
            }
        }
        ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response);
    }

    /**
     * 获取批量导入用户失败列表
     */
    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
    @SaCheckPermission("system:user:export")
    @PostMapping("/exportFailUsers")
    public void exportFailUsers(HttpServletResponse response) {
        String key = GlobalConstants.BATCH_IMPORT_FAIL_USERS + LoginHelper.getUserId();
        ExcelUtil.exportExcel(RedisUtils.getCacheList(key), "用户数据", SysUserImportVo.class, response);
        RedisUtils.deleteObject(key);
    }

    /**
     * 导入数据
     *
     * @param file          导入文件
     * @param updateSupport 是否更新已存在数据
     */
    @Log(title = "用户管理", businessType = BusinessType.IMPORT)
    @SaCheckPermission("system:user:import")
    @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<List<SysUserImportVo>> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception {
        //ExcelResult<SysUserImportVo> result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport));
        //List<SysUserImportVo> resultList = result.getList();
        //if (!resultList.isEmpty()) {
        //    String key = GlobalConstants.BATCH_IMPORT_FAIL_USERS + LoginHelper.getUserId();
        //    RedisUtils.setCacheList(key, resultList);
        //    return R.fail(resultList);
        //}
        //return R.ok(result.getAnalysis());

        //识别Excel内容
        List<SysUserImportVo> userImportList = new ExcelUtils<>(SysUserImportVo.class).importExcel(file.getInputStream(), 2);
        if (userImportList.isEmpty()) {
            throw new ServiceException("表格中不存在待导入数据!");
        }

        //开始导入业务
        List<SysUserImportVo> failImportUsers = userService.batchImportUser(userImportList, updateSupport);

        //将导入失败用户存入Redis并返回给前端
        if (!failImportUsers.isEmpty()) {
            String key = GlobalConstants.BATCH_IMPORT_FAIL_USERS + LoginHelper.getUserId();
            //删除旧的
            RedisUtils.deleteObject(key);
            //写入新的
            RedisUtils.setCacheList(key, failImportUsers);
            return R.fail(failImportUsers);
        }

        return R.ok();
    }

    /**
     * 获取导入模板
     */
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) {
        List<Object> list = new ArrayList<>();
        list.add(new SysUserImportVo("重庆市轨道交通（集团）有限公司", "刘国海", "18888888888", "运营部部长"));
        ExcelUtil.exportTemplate(list, "用户数据", "excel/userImportTemplate.xlsx", response);
    }

    /**
     * 根据用户编号获取详细信息
     *
     * @param userId 用户ID
     */
    @SaCheckPermission("system:user:query")
    @GetMapping(value = {"/", "/{userId}"})
    public R<Map<String, Object>> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
        userService.checkUserDataScope(userId);
        Map<String, Object> ajax = new HashMap<>();
        List<SysRole> roles = roleService.selectRoleAll();
        ajax.put("roles", LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin()));
        ajax.put("posts", postService.selectPostAll());
        if (ObjectUtil.isNotNull(userId)) {
            SysUser sysUser = userService.selectUserById(userId);
            ajax.put("user", BeanUtil.toBean(sysUser, SysUserVo.class));
            ajax.put("postIds", postService.selectPostListByUserId(userId));
            ajax.put("roleIds", StreamUtils.toList(sysUser.getRoles(), SysRole::getRoleId));
        }
        return R.ok(ajax);
    }

    /**
     * 新增用户
     */
    @SaCheckPermission("system:user:add")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @PostMapping
    public R<Void> add(@Validated @RequestBody SysUser user) {
        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
            return R.fail("新增用户'" + user.getUserName() + "'失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
            return R.fail("新增用户'" + user.getUserName() + "'失败，邮箱账号已存在");
        }
        return toAjax(userService.insertUser(user));
    }

    /**
     * 修改用户
     */
    @SaCheckPermission("system:user:edit")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<Void> edit(@Validated @RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        if (!userService.checkUserNameUnique(user)) {
            return R.fail("修改用户'" + user.getUserName() + "'失败，登录账号已存在");
        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
            return R.fail("修改用户'" + user.getUserName() + "'失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
            return R.fail("修改用户'" + user.getUserName() + "'失败，邮箱账号已存在");
        }
        return toAjax(userService.updateUser(user));
    }

    /**
     * 删除用户
     *
     * @param userIds 角色ID串
     */
    @SaCheckPermission("system:user:remove")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public R<Void> remove(@PathVariable Long[] userIds) {
        //不能删除当前登录账号
        if (ArrayUtil.contains(userIds, getUserId())) {
            return R.fail("当前用户不能删除");
        }
        return toAjax(userService.deleteUserByIds(userIds));
    }

    /**
     * 重置密码
     */
    @SaCheckPermission("system:user:resetPwd")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetPwd")
    public R<Void> resetPwd(@RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setPassword(BCrypt.hashpw(new String(Base64.getDecoder().decode(user.getPassword()))));
        return toAjax(userService.resetPwd(user));
    }

    /**
     * 状态修改
     */
    @SaCheckPermission("system:user:edit")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public R<Void> changeStatus(@RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        return toAjax(userService.updateUserStatus(user));
    }

    /**
     * 根据用户编号获取授权角色
     *
     * @param userId 用户ID
     */
    @SaCheckPermission("system:user:query")
    @GetMapping("/authRole/{userId}")
    public R<Map<String, Object>> authRole(@PathVariable Long userId) {
        SysUser user = userService.selectUserById(userId);
        List<SysRole> roles = roleService.selectRolesByUserId(userId);
        Map<String, Object> ajax = new HashMap<>();
        ajax.put("user", user);
        ajax.put("roles", LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin()));
        return R.ok(ajax);
    }

    /**
     * 用户授权角色
     *
     * @param userId  用户Id
     * @param roleIds 角色ID串
     */
    @SaCheckPermission("system:user:edit")
    @Log(title = "用户管理", businessType = BusinessType.GRANT)
    @PutMapping("/authRole")
    public R<Void> insertAuthRole(Long userId, Long[] roleIds) {
        userService.checkUserDataScope(userId);
        userService.insertUserAuth(userId, roleIds);
        return R.ok();
    }

    /**
     * 获取部门树列表
     */
    @SaCheckPermission("system:user:list")
    @GetMapping("/deptTree")
    public R<List<Tree<Long>>> deptTree(SysDept dept) {
        return R.ok(deptService.selectDeptTreeList(dept));
    }

}
