package cn.api.system;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.code.kaptcha.Producer;
import cn.facade.abs.IService;
import cn.common.annotation.Log;
import cn.common.enums.BizOpType;
import cn.common.enums.ResultCode;
import cn.logger.AsyncLoggingFactory;
import cn.common.page.response.Result;
import cn.constant.CommonConst;
import cn.pojo.entity.TSysUser;
import cn.pojo.vo.LoginUser;
import cn.schedule.core.AsyncManager;
import cn.service.system.IFacadeService;
import cn.util.codec.Base64;
import cn.util.codec.EncryKit;
import cn.util.core.IsKit;
import cn.util.core.LogKit;
import cn.util.core.TypeKit;
import cn.util.core.ServletKit;
import cn.util.string.JsonKit;
import cn.util.uuid.UUIDKit;

@RestController
@RequestMapping("/api/facade")
public class FacadeCtrl extends IService
{
	@Resource
	private IFacadeService facadeService;

	//**************以下代码对应用户登陆与退出业务**********************/
	/**用户退出:token加密后的值;*/
	@PostMapping("/logout/{token}")
	@Log(title = "主页面-用户退出-logout", businessType = BizOpType.FORCE)
	public void logout(@PathVariable String token) 
	{
		LoginUser loginUser = facadeService.getLoginUser(token);
		if (IsKit.isNotNull(loginUser)) {
			String userName = loginUser.getUsername();
			//删除用户缓存记录 解密后的值
			facadeService.delLoginUser(loginUser.getToken());
			//记录用户退出日志
			AsyncManager.me().execute(AsyncLoggingFactory.insertLoginInfo(userName,CommonConst.LOGOUT, "退出成功"));
		}
		ServletKit.renderString(ServletKit.getResponse(), JSON.toJSONString(Result.ok(ResultCode.HTTP_SUCCESS.getCode(),"退出成功")));
	}
	
	/**用户获取到token和角色信息后(/login),获取用户信息*/
	@GetMapping(value="/getUserInfoByRole/{roleCode}")
	@Log(title = "登录页面-获取用户信息-getUserInfoByRole",businessType = BizOpType.SELECT)
	public Result<?> getUserInfoByRole(@PathVariable String roleCode)
	{
		//获取登录用户token信息，即signIn时已缓存起来的信息
		LoginUser loginUser = facadeService.getLoginUser(ServletKit.getRequest());
		if(IsKit.isNull(loginUser)) {
			return Result.warnMsg(ResultCode.HTTP_UNAUTHORIZED.getMsg());
		}
		Map<String, Object> resultMap = loginUser.getUserMap();
		//登录用户信息
		String roleId = TypeKit.objToStr(resultMap.get("roleIds"));
		//按钮权限
		resultMap.put("btnPerm",sysBaseService.getBtnPerm(roleId,roleCode));
		//菜单权限与数据范围
		resultMap.put("menuPerm", sysBaseService.getMenuPerm(roleId,roleCode));
		return Result.ok(resultMap);
	}

	/**用户登录*/
	@PostMapping("/login")
	@Log(title = "登录页面-返回Token和角色-login", businessType = BizOpType.SELECT)
	public Result<?> login(@RequestBody Map<String,String> loginBody) 
	{
		// 校验验证码
		String verifyCode = facadeService.verifyCode(loginBody);
		if(IsKit.isNotNull(verifyCode)) {
			return Result.ok(verifyCode);
		}
		//生成加密后的令牌返回页面,同时保存用户信息到缓存(验证通过)
		String token = facadeService.loginToken(loginBody);
		Map<String, Object> result = new HashMap<>();
		result.put("token", token);
		//返回用户角色信息: 对于多角色用户需要用户确定角色后，系统给才能进入主页面
		result.put("role", sysBaseService.getUserRole(loginBody));
		return Result.ok(result);
	}

	/**生成页面上的验证码**/
	//验证码类型
	@Value("${sam.sys.kaptchaType}")
	private String captchaType = "math";
	@Resource(name = "captchaProducer")
	private Producer captchaProducer;
	@Resource(name = "captchaProducerMath")
	private Producer captchaProducerMath;

	@GetMapping("/captchaImage")
	@Log(title = "登录页面-生成验证码-captchaImage", businessType = BizOpType.SELECT)
	public Result<?> captchaImage(){
		//保存验证码信息
		String uuid = UUIDKit.simpleUUID();
		String verifyKey = CommonConst.CAPTCHA_CODE_KEY + uuid;

		String capStr;
		String code = null;
		BufferedImage image = null;
		// 生成验证码
		if ("math".equals(captchaType)) {
			String capText = captchaProducerMath.createText();
			capStr = capText.substring(0, capText.lastIndexOf("@"));
			code = capText.substring(capText.lastIndexOf("@") + 1);
			image = captchaProducerMath.createImage(capStr);
		}
		else if ("char".equals(captchaType)) {
			capStr = code = captchaProducer.createText();
			image = captchaProducer.createImage(capStr);
		}
		if(IsKit.isNull(image)){
			return Result.warnMsg(ResultCode.USER_VERIFICATION_CODE_FAIL.getMsg());
		}
		redisCache.setCacheObject(verifyKey,code,CommonConst.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
		//转换流信息写出
		FastByteArrayOutputStream os = new FastByteArrayOutputStream();
		try {
			ImageIO.write(image, "jpg", os);
		} catch (IOException e) {
			return Result.warnMsg(ResultCode.USER_VERIFICATION_CODE_FAIL.getMsg());
		}
		Map<String, Object> result = new HashMap<>();
	    result.put("uuid", uuid);
		result.put("img", Base64.encode(os.toByteArray()));
		return Result.ok(result);
	}
	
	//**************以下代码对应前端用户个人信息维护页面**********************/
	/**依据用户角色获取用户信息*/
	@GetMapping(value="/getUserInfoByAccount/{roleId}")
	@Log(title = "个人信息维护-获取用户信息-getUserInfoByAccount", businessType = BizOpType.SELECT)
	public Result<?> getUserInfoByAccount(@PathVariable String roleId)
	{
		//获取登录用户的相关信息，即signIn时已缓存起来的信息
		LoginUser loginUser = facadeService.getLoginUser(ServletKit.getRequest());
		Map<String, Object> resultMap = loginUser.getUserMap();
		//权限字符串
		resultMap.put("roleKey",sysBaseService.getRolekey(roleId));
		//角色权限
		resultMap.put("rolePerm",sysBaseService.getRoleperm(roleId));
		return Result.ok(resultMap);
	}

	/**修改用户个人信息。使用JSONObject的原因(解析[])。由于页面数据格式"roleIds":[1,2]*/
	@PutMapping("/updateUserInfo")
	@Log(title = "个人信息维护-更新用户信息-updateUserInfo", businessType = BizOpType.UPDATE)
	public Result<?> updateUserInfo(@RequestBody JSONObject jsonData) 
	{
		TSysUser entity = JsonKit.json2Bean_fast(jsonData,TSysUser.class);
		if(IsKit.isNull(entity)){
			Result.warnMsg(ResultCode.PARAM_ERR.getMsg());
		}
		if (IsKit.isNotNullOrEmpty(entity.getPhonenumber()) && !daoService.isUnique(entity, "user_id","phonenumber")){
			return Result.warnMsg( "修改用户'" + entity.getUserName() + "'失败，手机号码已存在");
		}
		//new String[] {"user_id","email"})
		if (IsKit.isNotNullOrEmpty(entity.getEmail()) && !daoService.isUnique(entity, "user_id","email")) {
			return Result.warnMsg("修改用户'" + entity.getUserName() + "'失败，邮箱账号已存在");
		}
		String password = entity.getPassword();
		if(IsKit.isNullOrEmpty(password)) {
			//设置默认密码123456
			password = EncryKit.encryptPassword(CommonConst.DEFAULT_PWD);
		}
		entity.setPassword(password);
		//成功保存后，需要更新缓存中的用户信息
		if (daoService.update(entity) > 0)
		{
			//此用户原信息
			LoginUser loginUser = facadeService.getLoginUser(ServletKit.getRequest());
			Map<String, Object> userMap = JsonKit.entityToMap(entity);
			//设置部门信息 用户有可能修订了部门信息	facadeService.setDeptInfo(userMap);
			userMap.put("dept", sysBaseService.getDeptInfo(entity.getDeptId()));
			loginUser.setUser(userMap);
			facadeService.setLoginUser(loginUser);
			return Result.ok();
		}
		return Result.warnMsg("修改个人信息异常，请联系管理员");
	}
	
     /**重置密码 */
	@PostMapping("/updatePwd")
	@Log(title = "个人信息维护-重置密码-updateUserPwd", businessType = BizOpType.UPDATE)
	public Result<?> updateUserPwd(@RequestBody Map<String,String> paramMap)
	{
		String oldPassword = paramMap.get("password"); 
		String newPassword= paramMap.get("newPassword"); 
		LoginUser loginUser = facadeService.getLoginUser(ServletKit.getRequest());
		Map<String, Object> userMap = loginUser.getUserMap();
		String password = loginUser.getPassword();
		if (!EncryKit.matchesPassword(oldPassword, password)) {
			return Result.warnMsg("修改密码失败，旧密码错误");
		}
		if (EncryKit.matchesPassword(newPassword, password)) {
			return Result.warnMsg("新密码不能与旧密码相同");
		}
		try {
			if (sysBaseService.resetUserPwd(
					TypeKit.objToInt(userMap.get("userId")),
					EncryKit.encryptPassword(newPassword)))
			{
				//更新缓存用户密码
				userMap.put("password",EncryKit.encryptPassword(newPassword));
				loginUser.setUser(userMap);
				facadeService.setLoginUser(loginUser);
				return Result.ok();
			}
		} catch (Exception e) {
			LogKit.info(e);
			return Result.warnMsg("修改密码异常");
		}
		return Result.warnMsg("修改密码异常，请联系管理员");
	}

	/** 上传头像上传. formData格式数据*/
	@PostMapping("/uploadFile")
	@Log(title = "个人信息维护-头像上传-uploadUserAvatar", businessType = BizOpType.UPDATE)
	public Result<?> uploadFile(@RequestParam("avatarfile") MultipartFile file,
			@RequestParam("fileName") String fileName)
	{
		LoginUser loginUser = facadeService.getLoginUser(ServletKit.getRequest());
		Map<String, Object> userMap = loginUser.getUserMap();
		try {
			//保存文件，返回文件名
			String avatar = uploadFileService.uploadFile(file,fileName,"avatar");
			//目前是用user_name作为用户的照片的唯一名字
			if (IsKit.isNotNull(avatar) &&
				sysBaseService.updateUserAvatar(TypeKit.objToInt(userMap.get("userId")),avatar)) 
			{
				//更新缓存用户头像
				userMap.put("avatar",avatar);
				loginUser.setUser(userMap);
				facadeService.setLoginUser(loginUser);
				//返回页面
				Map<String, Object> resultData = new HashMap<>();
				resultData.put("avatar",avatar);
				return Result.ok(resultData);
			}
		} catch (Exception e) {
			LogKit.info(e);
			return Result.warnMsg(ResultCode.FILE_UPLOAD.getMsg());
		}
		return Result.warnMsg(ResultCode.FILE_UPLOAD.getMsg());
	}

	@GetMapping(value="/encryPwd/{pwd}")
	@Log(title = "密码维护-密码加密-encryPwd", businessType = BizOpType.SELECT)
	public Result<?> encryPwd(@PathVariable String pwd)
	{
		if(IsKit.isNullOrEmpty(pwd)){
			pwd = CommonConst.DEFAULT_PWD;
		}
		//获取登录用户的相关信息，即signIn时已缓存起来的信息
		return Result.ok(EncryKit.encryptPassword(pwd));
	}
}
