/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.api.controller;

import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.PhoneUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import org.springblade.common.cache.ParamCache;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.jwt.JwtUtil;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.sms.model.SmsCode;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.core.tool.utils.*;
import org.springblade.modules.auth.enums.UserEnum;
import org.springblade.modules.auth.provider.ITokenGranter;
import org.springblade.modules.auth.provider.TokenGranterBuilder;
import org.springblade.modules.auth.provider.TokenParameter;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.platform.entity.UserRecom;
import org.springblade.modules.platform.entity.UserScores;
import org.springblade.modules.platform.service.IUserRecomService;
import org.springblade.modules.platform.service.IUserScoresService;
import org.springblade.modules.resource.builder.sms.SmsBuilder;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserApp;
import org.springblade.modules.system.entity.UserInfo;
import org.springblade.modules.system.service.IUserService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;

import static org.springblade.core.cache.constant.CacheConstant.USER_CACHE;
import static org.springblade.modules.resource.utils.SmsUtil.VALIDATE_FAIL;
import static org.springblade.modules.resource.utils.SmsUtil.VALIDATE_SUCCESS;

/**
 * 控制器
 *
 * @author xuwei
 * @since 2022-02-12
 */
@RestController
@AllArgsConstructor
@RequestMapping(CommonConstant.API_URL)
@Api(value = "登录注册", tags = "01.登录注册")
public class Api01Controller extends BladeController {

	private final IUserService userService;
	private final IUserRecomService userRecomService;
	private final IUserScoresService userScoresService;
	private final BladeRedis bladeRedis;
	private final JwtProperties jwtProperties;

	@ApiLog("用户注册")
	@PostMapping("/user-register")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "用户注册", notes = "手机号注册")
	@Transactional(rollbackFor = Exception.class)
	public R userRegister(@ApiParam(value = "邀请码", required = true) @RequestParam(value = "inviteCode", required = false) String inviteCode,
						  @ApiParam(value = "手机号", required = true) @RequestParam(value = "phone") String phone,
						  @ApiParam(value = "密码", required = true) @RequestParam(value = "password") String password,
						  @ApiParam(value = "验证码", required = true) @RequestParam(value = "captchaCode", required = false) String captchaCode,
						  @ApiParam(value = "验证ID, 发送验证码返回的ID", required = true) @RequestParam(value = "captchaId") String captchaId){
		if(StringUtil.isEmpty(inviteCode)){
			inviteCode = "TPSL5I";
		}
		User query = userService.getOne(Wrappers.<User>query().lambda().eq(User::getCode, inviteCode));
		if (query == null){
			return R.fail("邀请码输入错误！");
		}
		if (!PhoneUtil.isPhone(phone)){
			return R.fail("请输入正确的手机号！");
		}
		if (StringUtil.isBlank(captchaCode) || StringUtil.isBlank(captchaId)){
			return R.fail("请输入手机验证码！");
		}
		User query1 = userService.getOne(Wrappers.<User>query().lambda().eq(User::getAccount, phone));
		if (query1 != null){
			return R.fail("手机号已注册！");
		}
		boolean flg = captchaCode(phone, captchaId, captchaCode);
		if (!flg){
			return R.fail(VALIDATE_FAIL);
		}
		String tenantId = WebUtil.getRequest().getHeader(TokenUtil.TENANT_HEADER_KEY);
		User user = new User();
		user.setAccount(phone);
		user.setPhone(phone);
		user.setTenantId(tenantId);
		user.setPassword(password);
		user.setName(DesensitizedUtil.mobilePhone(phone));
		CacheUtil.clear(USER_CACHE);
		flg = userService.registerApp(user, query.getId());
		if (flg){
			//添加用户推荐记录表数据
			query1 = userService.getOne(Wrappers.<User>query().lambda().eq(User::getAccount, phone));
			UserRecom userRecom = new UserRecom();
			userRecom.setUserId(query1.getId()); //团队用户
			userRecom.setRecomId(query.getId()); //推荐人
			userRecom.setCreateTime(DateUtil.now());
			userRecomService.save(userRecom);

			UserApp userApp = new UserApp();
			UserApp userAppQuery = userApp.selectOne(Wrappers.<UserApp>query().lambda().eq(UserApp::getUserId, query.getId()));
			//邀请好友注册完善资料（+5信誉分）
			UserScores userScores = new UserScores();
			userScores.setUserId(query.getId());//推荐人
			int score = Integer.parseInt(ParamCache.getValue(CommonConstant.SCORE_USER_REGISTER));
			userScores.setScore(score);
			String dataRemarks = "推荐用户注册";
			if (userAppQuery.getCreditScore() >= 500){
				score = Integer.parseInt(ParamCache.getValue(CommonConstant.SCORE_CONSIGN_REGISTER));
				userScores.setScore(score);
				dataRemarks = "推荐用户注册（500信誉分以上或含有500信誉分）";
			}
			userScores.setDataSrc("1");
			userScores.setDataId(query1.getId());
			userScores.setDataType(1);
			userScores.setDataRemarks(dataRemarks);
			userScoresService.save(userScores);
			//修改用户信誉积分
			UserApp userAppUpdate = new UserApp();
			userAppUpdate.setId(userAppQuery.getId());
			userAppUpdate.setCreditScore(userAppQuery.getCreditScore() + score);
			userAppUpdate.updateById();
			return R.success("注册成功");
		}else{
			return R.success("注册失败");
		}
	}

	@ApiLog("登录用户验证-账号密码")
	@PostMapping("/login_account")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "账号密码登录", notes = "账号:account,密码:password")
	public R accountLogin(@ApiParam(value = "账号", required = true) @RequestParam String username,
						  @ApiParam(value = "密码", required = true) @RequestParam String password) {

		String tenantId = WebUtil.getRequest().getHeader(TokenUtil.TENANT_HEADER_KEY);
		String grantType = WebUtil.getRequest().getParameter("grant_type");
		String refreshToken = WebUtil.getRequest().getParameter("refresh_token");
		String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), UserEnum.APP.getName());
		TokenParameter tokenParameter = new TokenParameter();
		tokenParameter.getArgs().set("tenantId", tenantId)
			.set("username", username)
			.set("password", DigestUtil.md5Hex(password))
			.set("grantType", grantType)
			.set("refreshToken", refreshToken)
			.set("userType", userType);
		ITokenGranter granter = TokenGranterBuilder.getGranter(grantType);
		UserInfo userInfo = granter.grant(tokenParameter);
		if (userInfo == null || userInfo.getUser() == null) {
			return R.fail("用户名或密码不正确");
		}

		return R.data(TokenUtil.createAuthInfo(userInfo));
	}

	@ApiLog("登录用户验证-手机验证码登录")
	@PostMapping("/login_phone")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "手机验证码登录", notes = "账号:account,密码:password")
	public R phoneLogin(@ApiParam(value = "账号", required = true) @RequestParam String username,
						@ApiParam(value = "验证码", required = true) @RequestParam(value = "captchaCode") String captchaCode,
						@ApiParam(value = "验证ID, 发送验证码返回的ID", required = true) @RequestParam(value = "captchaId") String captchaId) {
		if (!PhoneUtil.isPhone(username)){
			return R.fail("请输入正确的手机号！");
		}
		if (StringUtil.isEmpty(captchaCode) ||StringUtil.isEmpty(captchaId)){
			return R.fail("请输入手机验证码！");
		}
		String tenantId = WebUtil.getRequest().getHeader(TokenUtil.TENANT_HEADER_KEY);
		String grantType = "phone";
		String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), UserEnum.APP.getName());
		TokenParameter tokenParameter = new TokenParameter();
		tokenParameter.getArgs().set("tenantId", tenantId)
			.set("username", username)
			.set("captchaId", captchaId)
			.set("captchaCode", captchaCode)
			.set("grantType", grantType)
			.set("userType", userType);
		ITokenGranter granter = TokenGranterBuilder.getGranter(grantType);
		UserInfo userInfo = granter.grant(tokenParameter);
		return R.data(TokenUtil.createAuthInfo(userInfo));
	}


	@ApiLog("修改密码")
	@PostMapping("/reset_password")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "修改密码", notes = "账号:account,密码:password")
	public R resetPassword(@ApiParam(value = "手机号", required = true) @RequestParam String username,
						   @ApiParam(value = "密码", required = true) @RequestParam String password,
						   @ApiParam(value = "验证码", required = true) @RequestParam(value = "captchaCode") String captchaCode,
						   @ApiParam(value = "验证ID, 发送验证码返回的ID", required = true) @RequestParam(value = "captchaId") String captchaId) {
		String tenantId = WebUtil.getRequest().getHeader(TokenUtil.TENANT_HEADER_KEY);
		if (!PhoneUtil.isPhone(username)){
			return R.fail("请输入正确的手机号！");
		}
		if (StringUtil.isEmpty(captchaCode) ||StringUtil.isEmpty(captchaId)){
			return R.fail("请输入手机验证码！");
		}
		User user = userService.userByAccount(tenantId, username);
		if (user == null){
			return R.fail("该手机号为注册！");
		}
		boolean flg = captchaCode(username, captchaId,captchaCode);
		if (!flg){
			return R.fail(VALIDATE_FAIL);
		}
		User updateUser = new User();
		updateUser.setId(user.getId());
		updateUser.setPassword(DigestUtil.encrypt(password));
		flg = userService.updateById(updateUser);
		if (!flg){
			return R.fail("操作失败");
		}
		CacheUtil.clear(USER_CACHE);
		return R.success("操作成功");
	}

	@GetMapping("/logout")
	@ApiOperation(value = "退出登录")
	@ApiOperationSupport(order = 5)
	public R logout() {
		BladeUser user = AuthUtil.getUser();
		if (user != null && jwtProperties.getState()) {
			String token = JwtUtil.getToken(WebUtil.getRequest().getHeader(TokenConstant.HEADER));
			JwtUtil.removeAccessToken(user.getTenantId(), String.valueOf(user.getUserId()), token);
		}
		return R.success("退出成功");
	}

	private boolean captchaCode(String phone, String captchaId, String captchaCode){
		String key = "blade:sms::captcha:" + phone + ":" + captchaId;
		String cache = bladeRedis.get(key);
		if (captchaCode.equals(cache)){
			return true;
		}
		return false;
	}

}
