

package com.nantian.sc.cloud.admin.controller;

import cn.hutool.core.util.StrUtil;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nantian.sc.cloud.admin.api.dto.UserDTO;
import com.nantian.sc.cloud.admin.api.entity.SysUser;
import com.nantian.sc.cloud.admin.api.vo.UserVO;
import com.nantian.sc.cloud.admin.service.SysUserService;
import com.nantian.sc.cloud.admin.utils.PhoneCodeUtil;
import com.nantian.sc.cloud.common.core.constant.SecurityConstants;
import com.nantian.sc.cloud.common.core.exception.ValidateCodeException;
import com.nantian.sc.cloud.common.core.util.R;
import com.nantian.sc.cloud.common.log.annotation.SysLog;
import com.nantian.sc.cloud.common.security.annotation.Inner;
import com.nantian.sc.cloud.common.security.service.ScUser;
import com.nantian.sc.cloud.common.security.util.SecurityUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 *
 * @date 2018/12/16
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/user")
@Api(value = "user", tags = "用户管理模块")
public class SysUserController {
	private final SysUserService userService;

	@Autowired
	private RedisTemplate redisTemplate;

	/*修改用户信息*/
	@PostMapping("/updateInfo")
	public R updateInfo(@RequestBody SysUser user){
		return R.ok(userService.updateById(user));
	}

	/**
	 * 获取当前用户全部信息
	 *
	 * @return 用户信息
	 */
	@GetMapping(value = {"/info"})
	public R info() {
		String username = SecurityUtils.getUser().getUsername();
		Integer tenantId= SecurityUtils.getUser().getTenantId();
		SysUser user = userService.getOne(Wrappers.<SysUser>query()
				.lambda()
				.eq(SysUser::getUsername, username)
				.eq(SysUser::getTenantId,tenantId)
		       );
		if (user == null) {
			return R.failed(null, "获取当前用户信息失败");
		}
		return R.ok(userService.findUserInfo(user));
	}

	/**
	 * 获取当前用户全部信息
	 *
	 * @return 用户信息
	 */
	@GetMapping(value = {"/infoByPhone/{username}/{phone}"})
	public R infoByPhone(@PathVariable String username,@PathVariable String phone) {
		SysUser user = userService.getOne(Wrappers.<SysUser>query()
				.lambda()
				.eq(SysUser::getUsername, username)
				.eq(SysUser::getPhone,phone)
		);
		if (user == null) {
			return R.failed(null, "查询用户信息失败");
		}
		return R.ok("查询用户信息成功");
	}

	/**
	 * 获取指定用户全部信息
	 *
	 * @return 用户信息
	 */
	@Inner
	@GetMapping("/info/{username}")
	public R info(@PathVariable String username) {
		SysUser user = userService.getOne(Wrappers.<SysUser>query()
				.lambda().eq(SysUser::getUsername, username));
		if (user == null) {
			return R.failed(null, String.format("用户信息为空 %s", username));
		}
		return R.ok(userService.findUserInfo(user));
	}

	@GetMapping("/userInfo")
	public R info(SysUser user) {
		List<SysUser> list = userService.list(Wrappers.query(user));
		return R.ok(list);
	}

	/**
	 * 通过ID查询用户信息
	 *
	 * @param id ID
	 * @return 用户信息
	 */
	@GetMapping("/{id}")
	public R user(@PathVariable Integer id) {
		return R.ok(userService.selectUserVoById(id));
	}

	/**
	 * 根据用户名查询用户信息
	 *
	 * @param username 用户名
	 * @return
	 */
	@GetMapping("/details/{username}")
	public R user(@PathVariable String username) {
		SysUser condition = new SysUser();
		Integer tenantId= SecurityUtils.getUser().getTenantId();
		condition.setUsername(username);
		condition.setTenantId(tenantId);
		return R.ok(userService.getOne(new QueryWrapper<>(condition)));
	}

	/**
	 * 删除用户信息
	 *
	 * @param id ID
	 * @return R
	 */
	@SysLog("删除用户信息")
	@DeleteMapping("/{id}")
	@PreAuthorize("@pms.hasPermission('sys_user_del')")
	@ApiOperation(value = "删除用户", notes = "根据ID删除用户")
	@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "int", paramType = "path")
	public R userDel(@PathVariable Integer id) {
		SysUser sysUser = userService.getById(id);
		return R.ok(userService.deleteUserById(sysUser));
	}

	/**
	 * 添加用户
	 *
	 * @param userDto 用户信息
	 * @return success/false
	 */
	@SysLog("添加用户")
	@PostMapping
	@PreAuthorize("@pms.hasPermission('sys_user_add')")
	public R user(@RequestBody UserDTO userDto) {
		return R.ok(userService.saveUser(userDto));
	}

	/**
	 * 更新用户信息
	 *
	 * @param userDto 用户信息
	 * @return R
	 */
	@SysLog("更新用户信息")
	@PutMapping
	//@PreAuthorize("@pms.hasPermission('sys_user_edit')")
	public R updateUser(@Valid @RequestBody UserDTO userDto) {
		return R.ok(userService.updateUser(userDto));
	}

	@SysLog("修改用户密码")
	@PutMapping("/passwd")
	public R updateUserPassword(@RequestBody UserDTO userDto) {
		return R.ok(userService.updateUserPassword(userDto));
	}

	/**
	 * 分页查询用户
	 *
	 * @param page    参数集
	 * @param userDTO 查询参数列表
	 * @return 用户集合
	 */
	@GetMapping("/page")
	public R getUserPage(Page page, UserDTO userDTO) {
		return R.ok(userService.getUsersWithRolePage(page, userDTO));
	}

	/**
	 * 修改个人信息
	 *
	 * @param userDto userDto
	 * @return success/false
	 */
	@SysLog("修改个人信息")
	@PutMapping("/edit")
	public R updateUserInfo(@Valid @RequestBody UserDTO userDto) {
		return userService.updateUserInfo(userDto);
	}

	/**
	 * @param username 用户名称
	 * @return 上级部门用户列表
	 */
	@GetMapping("/ancestor/{username}")
	public R listAncestorUsers(@PathVariable String username) {
		return R.ok(userService.listAncestorUsers(username));
	}

	/**
	 * 获取账户分配、登录等信息
	 */
	@Inner(value=false)
	@GetMapping("/accountDetail")
	public R accountDetail(String start, String end) {
		return R.ok(userService.accountDetail(start,end));
	}

	@GetMapping("/getListEn")
	public R getListEn(@Param("query") String query){
		return R.ok(userService.list(
				new QueryWrapper<SysUser>().like("user_real_name", query)
						.eq("user_dept",1)));
	}
	/**
	 * 根据用户名查询登录错误次数
	 * @param username
	 * @return
	 */
	@Inner(value = false) //取消身份验证
	@GetMapping("/getUserLoginCount")
	public R getUserLoginCount(String username){
		if (username == null) return R.failed("用户名为空，请重新输入");
		SysUser sysUser = userService.getOne(new QueryWrapper<SysUser>().eq("username", username).eq("del_flag", "0"));
		if (sysUser != null){
			Date expirationTime = sysUser.getExpirationTime();
			int i = sysUser.getWrongNumber() == null ? 0 : sysUser.getWrongNumber();
			int flag = 5 - i;
			Map<String, Object> map = new HashMap<>();
			map.put("expirationTime", expirationTime);
			map.put("flag",flag);
			map.put("tel",sysUser.getPhone());
			return R.ok(map,"还剩余" + flag + "次机会！");
		}else {
			return R.ok(null, "系统不存在当前用户名！");
		}
	}

	/**
	 * 登录成功后取消用户登录错误次数
	 * @param username
	 * @return
	 */
	@Inner(value = false)
	@GetMapping("/setUserCount")
	public R setUserCount(String username){
		SysUser sysUser = userService.getOne(new QueryWrapper<SysUser>().eq("username", username).eq("del_flag", "0"));
//		UserDTO userDTO = new UserDTO();
//		BeanUtils.copyProperties(sysUser, userDTO);
		sysUser.setExpirationTime(null);
		sysUser.setWrongNumber(0);
		userService.updateById(sysUser);
		return R.ok();
	}

	/**
	 * 根据用户名查询用户密码输入错误次数
	 * @param username
	 * @return
	 */
	@Inner(value = false)
	@GetMapping("/updateUserLoginCount")
	public R updateUserLoginCount(String username){
		SysUser user = userService.getOne(new QueryWrapper<SysUser>().eq("username", username).eq("del_flag", "0"));
		if (user != null){
			int i = user.getWrongNumber() == null ? 0 : user.getWrongNumber();
			if (i + 1 < 5){
				user.setWrongNumber(i + 1);
				userService.updateById(user);
				int flag = 5 - (i + 1);
				return R.failed("密码输入错误，还剩余" + flag + "次机会！");
			}else if(i + 1 == 5){
				user.setWrongNumber(5);
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(new Date());
				calendar.add(Calendar.HOUR_OF_DAY, 1);
				user.setExpirationTime(calendar.getTime());
				userService.updateById(user);
				return R.failed("当前用户已被锁定，请在" + calendar.getTime() + "之后再尝试登录！");
			}else {
				return R.failed("当前用户已被锁定，请在" + user.getExpirationTime() + "之后再尝试登录！");
			}
		}else {
			return R.failed("系统无此用户，请检查用户名！");
		}
	}

	/**
	 * 根据用户手机号码获取验证码
	 */
	@Inner(value = false)
	@SneakyThrows
	@GetMapping("/getPhoneCode")
	public R getPhoneCode(String phone){
		String code = String.format("%04d",new Random().nextInt(9999));
		PhoneCodeUtil phoneCodeUtil = new PhoneCodeUtil();
		try {
			phoneCodeUtil.sendVerificationCode(phone, code);
		}catch (Exception e){
			e.getMessage();
		}
		String md5Hex = phone + code;
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.opsForValue().set("phone_code",md5Hex, SecurityConstants.CODE_TIME, TimeUnit.SECONDS);
		System.out.println(redisTemplate.opsForValue().get("phone_code"));
		log.info("手机验证码信息  ===phone：{}, ===code：{}, ===CODE_TIME：{}, ===SECONDS：{}, ===md5Hex: {}",
				phone, code, SecurityConstants.CODE_TIME, TimeUnit.SECONDS,md5Hex);
		return R.ok();
	}

	/**
	 * 手机登录验证码校验
	 * @param phone
	 * @param phoneCode
	 * @return
	 */
	@GetMapping("/checkPhoneCode")
	@SneakyThrows
	public R checkPhoneCode(String phone, String phoneCode){

		if (StringUtils.isBlank(phoneCode)){
			throw new ValidateCodeException("手机验证码不能为空");
		}

		String key = "phone_code";
		redisTemplate.setKeySerializer(new StringRedisSerializer());

		if (!redisTemplate.hasKey(key)) {
			throw new ValidateCodeException("手机验证码不合法");
		}

		Object codeObj = redisTemplate.opsForValue().get(key);
		if (codeObj == null) {
			throw new ValidateCodeException("手机验证码不合法");
		}

		String saveCode = codeObj.toString();
		if (StrUtil.isBlank(saveCode)) {
			redisTemplate.delete(key);
			throw new ValidateCodeException("手机验证码不合法");
		}

		String code = phone + phoneCode;

		if (!StrUtil.equals(saveCode, code)) {
			throw new ValidateCodeException("手机验证码不合法");
		}

		redisTemplate.delete(key);
		return R.ok();
	}
}
