package ink.wgink.service.user.controller.api;

import ink.wgink.annotation.CheckRequestBodyAnnotation;
import ink.wgink.common.base.DefaultBaseController;
import ink.wgink.common.component.SecurityComponent;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.interfaces.consts.IFileConstant;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.interfaces.manager.ISystemConfigManager;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.pojo.result.*;
import ink.wgink.pojo.vos.IdsVO;
import ink.wgink.pojo.vos.UpdatePasswordVO;
import ink.wgink.service.user.pojo.vos.RestPasswordVO;
import ink.wgink.service.user.pojo.vos.UpdateExpiredDateVO;
import ink.wgink.service.user.pojo.vos.UpdateUsernameVO;
import ink.wgink.service.user.pojo.vos.UserVO;
import ink.wgink.service.user.service.IUserService;
import ink.wgink.util.ReflectUtil;
import ink.wgink.util.RegexUtil;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: UserController
 * @Description: 用户
 * @Author: WangGeng
 * @Date: 2021/1/24 17:10
 * @Version: 1.0
 **/
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "用户")
@RestController
@RequestMapping(ISystemConstant.API_PREFIX + "/user")
public class UserController extends DefaultBaseController {

    @Autowired
    private IUserService userService;
    @Autowired
    private SecurityComponent securityComponent;

    @ApiOperation(value = "新增用户", notes = "新增用户接口")
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @PostMapping("save")
    public SuccessResult save(@RequestBody UserVO userVO) {
        checkParams(userVO);
        userService.save(userVO);
        return new SuccessResult();
    }

    @ApiOperation(value = "删除用户", notes = "删除用户接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "ids", value = "用户ID列表，用下划线分隔", paramType = "path")
    })
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @DeleteMapping("remove/{ids}")
    public SuccessResult remove(@PathVariable("ids") String ids) {
        userService.remove(Arrays.asList(ids.split("\\_")));
        return new SuccessResult();
    }

    @ApiOperation(value = "删除用户", notes = "删除用户接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "ids", value = "用户ID列表，用下划线分隔", paramType = "path")
    })
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @DeleteMapping("delete/user-id/{userId}")
    public SuccessResult deleteByUserId(@PathVariable("userId") String userId) {
        userService.delete(Arrays.asList(userId));
        return new SuccessResult();
    }

    @ApiOperation(value = "修改用户", notes = "修改用户接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户ID", paramType = "path"),
    })
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @PutMapping("update/{userId}")
    public SuccessResult update(@PathVariable("userId") String userId, @RequestBody UserVO userVO) {
        checkParams(userVO);
        userService.update(userId, userVO);
        return new SuccessResult();
    }

    /**
     * 参数校验
     *
     * @param userVO
     * @throws ParamsException
     */
    private void checkParams(UserVO userVO) throws ParamsException {
        if (!StringUtils.isBlank(userVO.getUserPhone()) && !RegexUtil.isPhone(userVO.getUserPhone())) {
            throw new ParamsException("手机号码格式错误");
        }
        if (!StringUtils.isBlank(userVO.getUserEmail()) && !RegexUtil.isEmail(userVO.getUserEmail())) {
            throw new ParamsException("用户邮箱格式错误");
        }
        if (!StringUtils.isBlank(userVO.getUserExpiredDate()) && !RegexUtil.isDatetime(userVO.getUserExpiredDate())) {
            throw new ParamsException("过期时间格式错误");
        }
    }

    @ApiOperation(value = "用户重置密码", notes = "用户重置密码接口")
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @PutMapping("reset-password/{userId}")
    @CheckRequestBodyAnnotation
    public SuccessResult resetPassword(@PathVariable("userId") String userId, @RequestBody RestPasswordVO restPasswordVO) {
        userService.resetPassword(userId, restPasswordVO);
        return new SuccessResult();
    }

    @ApiOperation(value = "用户修改用户名", notes = "用户修改用户名接口")
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @PutMapping("update-username/{userId}")
    @CheckRequestBodyAnnotation
    public SuccessResult updateUsername(@PathVariable("userId") String userId, @RequestBody UpdateUsernameVO updateUsernameVO) throws Exception {
        userService.updateUsername(userId, updateUsernameVO);
        return new SuccessResult();
    }

    @ApiOperation(value = "修改密码", notes = "修改密码接口")
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @PutMapping("update-password")
    @CheckRequestBodyAnnotation
    public SuccessResult updatePassword(@RequestBody UpdatePasswordVO updatePasswordVO) throws ReflectUtil.ReflectException {
        ISystemConfigManager systemConfigManager = ReflectUtil.getSingleInstance("ink.wgink.login.base.manager.ConfigManager", ISystemConfigManager.class);
        if (systemConfigManager != null) {
            checkUpdatePasswordParams(systemConfigManager.getConfig(), updatePasswordVO);
        }
        userService.updatePassword(updatePasswordVO);
        return new SuccessResult();
    }

    /**
     * 修改密码参数校验
     *
     * @param config
     * @param updatePasswordVO
     */
    private void checkUpdatePasswordParams(Map<String, String> config, UpdatePasswordVO updatePasswordVO) {
        if (config.get(IUserService.PASSWORD_STRENGTH) != null) {
            String passwordStrength = config.get(IUserService.PASSWORD_STRENGTH);
            if (StringUtils.equals(IUserService.PASSWORD_STRENGTH_MIDDLE, passwordStrength) && !RegexUtil.isPasswordMiddle(updatePasswordVO.getNewPassword())) {
                throw new ParamsException(String.format("密码应该%d到%d位，包含数字、字母、特殊字符，其中的任意两种，特殊字符包括%s", RegexUtil.PASSWORD_LENGTH_MIN, RegexUtil.PASSWORD_LENGTH_MAX, RegexUtil.SPECIAL_CHARACTERS));
            } else if (StringUtils.equals(IUserService.PASSWORD_STRENGTH_STRONG, passwordStrength) && !RegexUtil.isPasswordStrong(updatePasswordVO.getNewPassword())) {
                throw new ParamsException(String.format("密码应该%d到%d位，必须全部包含数字、字母、特殊字符三种，特殊字符包括%s", RegexUtil.PASSWORD_LENGTH_MIN, RegexUtil.PASSWORD_LENGTH_MAX, RegexUtil.SPECIAL_CHARACTERS));
            } else if (!RegexUtil.isPasswordWeek(updatePasswordVO.getNewPassword())) {
                throw new ParamsException(String.format("密码应该%d到%d位，仅包含数字，字母，特殊字符，其中的一种，特殊字符包括%s", RegexUtil.PASSWORD_LENGTH_MIN, RegexUtil.PASSWORD_LENGTH_MAX, RegexUtil.SPECIAL_CHARACTERS));
            }
        } else if (!RegexUtil.isPasswordWeek(updatePasswordVO.getNewPassword())) {
            throw new ParamsException(String.format("密码应该%d到%d位，仅包含数字，字母，特殊字符，其中的一种，特殊字符包括%s", RegexUtil.PASSWORD_LENGTH_MIN, RegexUtil.PASSWORD_LENGTH_MAX, RegexUtil.SPECIAL_CHARACTERS));
        }
    }

    @ApiOperation(value = "更新过期时间", notes = "更新过期时间接口")
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @PutMapping("update-expired-date/{userId}")
    @CheckRequestBodyAnnotation
    public SuccessResult updateExpiredDate(@PathVariable("userId") String userId, @RequestBody UpdateExpiredDateVO updateExpiredDateVO) throws Exception {
        userService.updateExpiredDate(userId, updateExpiredDateVO);
        return new SuccessResult();
    }

    @ApiOperation(value = "用户导入Excel", notes = "用户导入Excel接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "excel", value = "文件名称", paramType = "query"),
    })
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @PostMapping("importexcel")
    public UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException {
        if (Objects.isNull(excel)) {
            throw new ParamsException("Excel不能为空");
        }
        if (!excel.getOriginalFilename().endsWith(IFileConstant.EXCEL_SUFFIX_XLS) &&
                !excel.getOriginalFilename().endsWith(IFileConstant.EXCEL_SUFFIX_XLSX)) {
            throw new ParamsException("文件格式为Excel");
        }
        return userService.importExcel(excel);
    }

    @ApiOperation(value = "用户列表", notes = "用户列表接口")
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @GetMapping("list")
    public List<UserDTO> list() {
        Map<String, Object> params = requestParams();
        return userService.list(params);
    }

    @ApiOperation(value = "用户分页列表", notes = "用户分页列表接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", value = "当前页码", paramType = "query", dataType = "int", defaultValue = "1"),
            @ApiImplicitParam(name = "rows", value = "显示数量", paramType = "query", dataType = "int", defaultValue = "20"),
            @ApiImplicitParam(name = "keywords", value = "关键字", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "startTime", value = "开始时间", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "endTime", value = "结束时间", paramType = "query", dataType = "String")
    })
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @GetMapping("listpage")
    public SuccessResultList<List<UserDTO>> listPage(ListPage page) {
        Map<String, Object> params = requestParams();
        page.setParams(params);
        return userService.listPage(page);
    }

    @ApiOperation(value = "用户详情", notes = "用户详情接口")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户ID", paramType = "path")
    })
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @GetMapping("get/{userId}")
    public UserDTO getUser(@PathVariable("userId") String userId) {
        return userService.get(userId);
    }

    @ApiOperation(value = "通过ID列表获取用户列表", notes = "通过ID列表获取用户列表接口")
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @PostMapping("listbyids")
    public List<UserDTO> listByIds(@RequestBody IdsVO idsVO) {
        if (idsVO.getIds().isEmpty()) {
            throw new ParamsException("id列表不能为空");
        }
        return userService.listByUserIds(idsVO.getIds());
    }

    @ApiOperation(value = "获取密码状态", notes = "获取密码状态接口")
    @ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
    @GetMapping("get-password-status")
    public SuccessResultData<String> getPasswordStatus() {
        return userService.getPasswordStatus(securityComponent.getCurrentUser().getUserId());
    }

}
