package com.ktg.web.controller.system;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ktg.common.annotation.Log;
import com.ktg.common.constant.UserConstants;
import com.ktg.common.core.controller.BaseController;
import com.ktg.common.core.domain.AjaxResult;
import com.ktg.common.core.domain.entity.SysRole;
import com.ktg.common.core.domain.entity.SysUser;
import com.ktg.common.core.page.TableDataInfo;
import com.ktg.common.enums.BusinessType;
import com.ktg.common.exception.ServiceException;
import com.ktg.common.utils.SecurityUtils;
import com.ktg.common.utils.StringUtils;
import com.ktg.common.utils.bean.BeanValidators;
import com.ktg.common.utils.poi.ExcelUtil;
import com.ktg.iscs.domain.IsUnit;
import com.ktg.iscs.domain.IsUserUnit;
import com.ktg.iscs.domain.IsUserWorkstation;
import com.ktg.iscs.service.IIsUnitService;
import com.ktg.iscs.service.IIsUserUnitService;
import com.ktg.iscs.service.IIsUserWorkstationService;
import com.ktg.system.domain.SysUserRole;
import com.ktg.system.mapper.SysUserRoleMapper;
import com.ktg.system.service.ISysConfigService;
import com.ktg.system.service.ISysPostService;
import com.ktg.system.service.ISysRoleService;
import com.ktg.system.service.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
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.Validator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户信息
 *
 * @author ruoyi
 */
@Slf4j
@Api(tags = "用户管理")
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController
{
    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysPostService postService;
    @Autowired
    private IIsUserWorkstationService iIsUserWorkstationService;
    @Autowired
    private IIsUserUnitService iIsUserUnitService;
    @Autowired
    private IIsUnitService iIsUnitService;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    protected Validator validator;
    @Autowired
    protected ISysRoleService iSysRoleService;
    @Autowired
    private SysUserRoleMapper userRoleMapper;

    /**
     * 获取用户列表
     */
    @GetMapping("/list")
    public TableDataInfo list(SysUser user)
    {
        List<SysUser> list = userService.selectUserList(user);
        return getDataTable(list);
    }

    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
    @PreAuthorize("@ss.hasPermi('system:user:export')")
    @PostMapping("/export")
    public void export(HttpServletResponse response, SysUser user)
    {
        user.setB(false);
        List<SysUser> list = userService.selectUserList(user);
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        util.exportExcel(response, list, "用户数据");
    }

    @Transactional
    @Log(title = "用户管理-导入", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('system:user:import')")
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
    {
        String filename = file.getOriginalFilename();
        String extension = FilenameUtils.getExtension(filename);
        // 文件不是 .xlsx 或 .xls
        Assert.isFalse(!"xls".equalsIgnoreCase(extension) && !"xlsx".equalsIgnoreCase(extension), "文件不是xls或xlsx，请重新上传！");
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        List<SysUser> userList = util.importExcel(file.getInputStream());
        String operName = getUsername();
        // String message = userService.importUser(userList, updateSupport, operName);

        if (StringUtils.isNull(userList) || userList.size() == 0) {
            throw new ServiceException("导入用户数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        String password = configService.selectConfigByKey("sys.user.initPassword");
        for (SysUser user : userList) {
            try {
                // 验证是否存在这个用户
                SysUser u = userService.selectUserByUserName(user.getUserName());
                if (StringUtils.isNull(u)) {
                    BeanValidators.validateWithException(validator, user);
                    user.setPassword(SecurityUtils.encryptPassword(password));
                    user.setCreateBy(operName);
                    userService.insertUser(user);
                    // 新增单位和角色关联关系
                    addUserUnit(user, false);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
                } else if (updateSupport) {
                    BeanValidators.validateWithException(validator, user);
                    user.setUpdateBy(operName);
                    userService.updateUser(user);
                    // 先删除再新增
                    addUserUnit(user, true);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return AjaxResult.success(successMsg.toString());
    }

    public Boolean addUserUnit(SysUser user, Boolean b) {
        // b新增不需清理以前数据，更新需要
        // 检查单位是否存在
        if (StringUtils.isNotBlank(user.getUnitName())) {
            IsUnit unit = iIsUnitService.getOne(Wrappers.<IsUnit>lambdaQuery()
                    .eq(IsUnit::getUnitName, user.getUnitName()));
            if (unit != null) {
                if (b) {
                    // 更新时先清理
                    iIsUserUnitService.remove(Wrappers.<IsUserUnit>lambdaQuery().eq(IsUserUnit::getUserId, user.getUserId()));
                }
                IsUserUnit isUserUnit = new IsUserUnit();
                isUserUnit.setUserId(user.getUserId());
                isUserUnit.setUnitId(unit.getUnitId());
                iIsUserUnitService.save(isUserUnit);
            }
        }
        // 检查角色是否存在
        if (StringUtils.isNotBlank(user.getRoleName())) {
            List<String> roleNames = Arrays.asList(user.getRoleName().split(",")).stream()
                    .map(String::trim) // 去除前后空格
                    .map(s -> s.replaceAll("\\s+", "")) // 去除所有空白字符（包括空格、制表符、换行符等）
                    .collect(Collectors.toList());
            if (!roleNames.isEmpty()) {
                List<SysRole> sysRoles = iSysRoleService.list(Wrappers.<SysRole>lambdaQuery().in(SysRole::getRoleName, roleNames));
                if (b) {
                    // 更新时先清理
                    userRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getUserId, user.getUserId()));
                }
                ArrayList<SysUserRole> sysUserRoles = new ArrayList<>();
                for (SysRole sysRole : sysRoles) {
                    SysUserRole sysUserRole = new SysUserRole();
                    sysUserRole.setUserId(user.getUserId());
                    sysUserRole.setRoleId(sysRole.getRoleId());
                    sysUserRoles.add(sysUserRole);
                }
                userRoleMapper.insertBatch(sysUserRoles);
            }
        }
        return true;
    }

    @ApiOperation("用户数据导入模板")
    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response)
    {
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        util.importTemplateExcel(response, "用户数据");
    }

    /**
     * 根据用户编号获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping(value = { "/", "/{userId}" })
    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
    {
        userService.checkUserDataScope(userId);
        AjaxResult ajax = AjaxResult.success();
        List<SysRole> roles = roleService.selectRoleAll();
        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        ajax.put("posts", postService.selectPostAll());
        if (StringUtils.isNotNull(userId))
        {
            SysUser sysUser = userService.selectUserById(userId);
            ajax.put(AjaxResult.DATA_TAG, sysUser);
            ajax.put("postIds", postService.selectPostListByUserId(userId));
            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
            ajax.put("workstationIds", iIsUserWorkstationService.selectWorkstationListByUserId(userId));
            ajax.put("unitIds", iIsUserUnitService.getUnitIds(userId));
        }
        return ajax;
    }

    /**
     * 新增用户
     */
    @Transactional
    @PreAuthorize("@ss.hasPermi('system:user:add')")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysUser user)
    {
        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName())))
        {
            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败，登录账号已存在");
        }
        else if (StringUtils.isNotEmpty(user.getPhonenumber())
                && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
        {
            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败，手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail())
                && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
        {
            return AjaxResult.error("新增用户'" + user.getUserName() + "'失败，邮箱账号已存在");
        }
        user.setCreateBy(getUsername());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        user.setKeyCode(user.getKeyCode());
        userService.insertUser(user);
        // 关联岗位
        if (user.getWorkstationIds() != null && user.getWorkstationIds().length > 0) {
            ArrayList<IsUserWorkstation> isUserWorkstations = new ArrayList<>();
            for (Long workstationId : user.getWorkstationIds()) {
                IsUserWorkstation isUserWorkstation = new IsUserWorkstation();
                isUserWorkstation.setUserId(user.getUserId());
                isUserWorkstation.setWorkstationId(workstationId);
                isUserWorkstations.add(isUserWorkstation);
            }
            // iIsUserWorkstationService.saveBatch(isUserWorkstations);
            for (IsUserWorkstation isUserWorkstation : isUserWorkstations) {
                iIsUserWorkstationService.save(isUserWorkstation);
            }
        }
        // 关联单位
        if (user.getUnitIds() != null && user.getUnitIds().length > 0) {
            ArrayList<IsUserUnit> userUnits = new ArrayList<>();
            for (Long unitId : user.getUnitIds()) {
                IsUserUnit isUserUnit = new IsUserUnit();
                isUserUnit.setUserId(user.getUserId());
                isUserUnit.setUnitId(unitId);
                userUnits.add(isUserUnit);
            }
            // iIsUserUnitService.saveBatch(userUnits);
            for (IsUserUnit userUnit : userUnits) {
                iIsUserUnitService.save(userUnit);
            }
        }
        return toAjax(true);
    }

    /**
     * 修改用户
     */
    @Transactional
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        if (StringUtils.isNotEmpty(user.getPhonenumber())
                && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
        {
            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败，手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail())
                && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
        {
            return AjaxResult.error("修改用户'" + user.getUserName() + "'失败，邮箱账号已存在");
        }
        user.setUpdateBy(getUsername());
        userService.updateUser(user);
        // 关联岗位
        if (user.getWorkstationIds() != null && user.getWorkstationIds().length > 0) {
            iIsUserWorkstationService.remove(Wrappers.<IsUserWorkstation>lambdaQuery()
                    .eq(IsUserWorkstation::getUserId, user.getUserId()));
            List<IsUserWorkstation> isUserWorkstations = new ArrayList<>();
            for (Long workstationId : user.getWorkstationIds()) {
                IsUserWorkstation isUserWorkstation = new IsUserWorkstation();
                isUserWorkstation.setUserId(user.getUserId());
                isUserWorkstation.setWorkstationId(workstationId);
                isUserWorkstations.add(isUserWorkstation);
                iIsUserWorkstationService.save(isUserWorkstation);
            }
            // iIsUserWorkstationService.saveBatch(isUserWorkstations);
        }
        // 关联单位
        if (user.getUnitIds() != null && user.getUnitIds().length > 0) {
            iIsUserUnitService.remove(Wrappers.<IsUserUnit>lambdaQuery()
                    .eq(IsUserUnit::getUserId, user.getUserId()));
            List<IsUserUnit> userUnits = new ArrayList<>();
            for (Long unitId : user.getUnitIds()) {
                IsUserUnit isUserUnit = new IsUserUnit();
                isUserUnit.setUserId(user.getUserId());
                isUserUnit.setUnitId(unitId);
                userUnits.add(isUserUnit);
                iIsUserUnitService.save(isUserUnit);
            }
            // iIsUserUnitService.saveBatch(userUnits);
        }
        return toAjax(true);
    }

    /**
     * 删除用户
     */
    @Transactional
    @PreAuthorize("@ss.hasPermi('system:user:remove')")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public AjaxResult remove(@PathVariable Long[] userIds)
    {
        if (ArrayUtils.contains(userIds, getUserId()))
        {
            return error("当前用户不能删除");
        }
        userService.deleteUserByIds(userIds);
        // 关联岗位
        if (userIds.length > 0) {
            iIsUserWorkstationService.remove(Wrappers.<IsUserWorkstation>lambdaQuery()
                    .in(IsUserWorkstation::getUserId, userIds));
        }
        // 关联单位
        if (userIds.length > 0) {
            iIsUserUnitService.remove(Wrappers.<IsUserUnit>lambdaQuery()
                    .in(IsUserUnit::getUserId, userIds));
        }
        return toAjax(true);
    }

    /**
     * 重置密码
     */
    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetPwd")
    public AjaxResult resetPwd(@RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        user.setUpdateBy(getUsername());
        return toAjax(userService.resetPwd(user));
    }

    /**
     * 重置钥匙密码
     */
    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetKeyCode")
    public AjaxResult resetKeyCode(@RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setKeyCode(user.getKeyCode());
        return toAjax(userService.resetKeyCode(user));
    }

    /**
     * 状态修改
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public AjaxResult changeStatus(@RequestBody SysUser user)
    {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setUpdateBy(getUsername());
        return toAjax(userService.updateUserStatus(user));
    }

    /**
     * 根据用户编号获取授权角色
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping("/authRole/{userId}")
    public AjaxResult authRole(@PathVariable("userId") Long userId)
    {
        AjaxResult ajax = AjaxResult.success();
        SysUser user = userService.selectUserById(userId);
        List<SysRole> roles = roleService.selectRolesByUserId(userId);
        ajax.put("user", user);
        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        return ajax;
    }

    /**
     * 用户授权角色
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.GRANT)
    @PutMapping("/authRole")
    public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
    {
        userService.checkUserDataScope(userId);
        userService.insertUserAuth(userId, roleIds);
        return success();
    }
}
