package org.springblade.gateway.login_gateway.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONObject;
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 lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springblade.common.utils.BeanPropertyUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.tool.api.R;
import org.springblade.gateway.login_gateway.service.LoginService;
import org.springblade.modules.resource.enums.SmsCodeEnum;
import org.springblade.modules.resource.utils.SmsUtil;
import org.springblade.sing.active.entity.ActiveProductRecord;
import org.springblade.sing.active.service.IActiveProductRecordService;
import org.springblade.sing.heat.entity.UserHeat;
import org.springblade.sing.heat.service.IUserHeatService;
import org.springblade.sing.point.entity.UserPufaPoint;
import org.springblade.sing.point.service.IUserPufaPointService;
import org.springblade.sing.user.entity.LoginUser;
import org.springblade.sing.user.service.ILoginUserService;
import org.springblade.wx.constant.MiniProgramType;
import org.springblade.wx.constant.ScopeTypeEnum;
import org.springblade.wx.service.WeChatService;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.*;


/**
 * @author cy-computer
 */
@RestController
@RequestMapping("/user/login")
@Api(value = "用户登录控制器", tags = "登录接口")
@AllArgsConstructor
public class LoginController {

	private final LoginService loginService;
	private final ILoginUserService loginUserService;
	private final IUserPufaPointService userPufaPointService;
	private final IUserHeatService userHeatService;
	private final IActiveProductRecordService activeProductRecordService;
	private final WeChatService weChatService;

	/**
	 * 小程序端全部返回false
	 * 判断是否为移动用户
	 */
	@GetMapping("/isCMCC")
	public R<Boolean> isCMCC(@ApiParam(value = "手机号", required = true) @RequestParam String phone) {
//		loginService.isCMCC(phone)
		return R.data(false);
	}

	/**
	 * H5 正常校验
	 *
	 * @param phone
	 * @return
	 */
	@GetMapping("/h5IsCMCC")
	public R<Boolean> h5IsCMCC(@ApiParam(value = "手机号", required = true) @RequestParam String phone) {
		return R.data(loginService.isCMCC(phone));
	}

	/**
	 * 保存用户的手机号
	 */
	@PostMapping("/savePhone")
	public R<Boolean> savePhone(@RequestParam String phone, @RequestParam Long userId) {
		synchronized (phone.intern()) {
			List<LoginUser> list = loginUserService.list(Condition.getQueryWrapper(new LoginUser()).lambda().eq(LoginUser::getPhone, phone));
			Assert.isTrue(CollUtil.isEmpty(list), "该手机号已被绑定");
			LoginUser loginUser = loginUserService.getById(userId);
			Assert.notNull(loginUser, "找不到该用户");
			loginUser.setPhone(phone);
			return R.status(loginUserService.updateById(loginUser));
		}
	}

	/**
	 * 修改用户手机号
	 */
	@PostMapping("/updatePhone")
	public R updatePhone(@RequestParam String oldPhone,
						 @RequestParam String newPhone,
						 @RequestParam String code,
						 @RequestParam String smsId,
						 @RequestParam Long userId) {
		LoginUser loginUser = loginUserService.getById(userId);
		Assert.notNull(loginUser, "找不到该用户");
		Assert.isTrue(Objects.equals(oldPhone, loginUser.getPhone()), "原手机号有误");
		Assert.isTrue(SmsUtil.validateMessage(SmsCodeEnum.VALIDATE.name(), smsId, code, newPhone), SmsUtil.VALIDATE_FAIL);
		List<LoginUser> list = loginUserService.list(Condition.getQueryWrapper(new LoginUser()).lambda().eq(LoginUser::getPhone, newPhone));
		Assert.isTrue(CollUtil.isEmpty(list), "该手机号已被绑定");
		loginUser.setPhone(newPhone);
		return R.data(loginUserService.updateById(loginUser));
	}

	/**
	 * 用户登录
	 */
	@PostMapping("/login")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "用户登录", notes = "传入loginUser")
	public R login(@Valid @RequestBody LoginUser loginUser) {
		synchronized (loginUser.getOpenid().intern()) {
			List<LoginUser> users = loginUserService.list(Wrappers.<LoginUser>lambdaQuery().eq(LoginUser::getOpenid, loginUser.getOpenid()).orderByDesc(LoginUser::getCreateTime));
			if (CollUtil.isEmpty(users)) {
				LoginUser user = new LoginUser();
				user.setAvatar(loginUser.getAvatar());
				user.setNickName(loginUser.getNickName());
				user.setOpenid(loginUser.getOpenid());
				user.setSex(loginUser.getSex());
				loginUserService.save(user);
				return R.data(user);
			}
			return R.data(users.get(0));
		}
	}

	/**
	 * 获取微信授权URL
	 */
	@GetMapping("/getH5WeixinAuthorizeUrl")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "获取微信授权URL")
	@SneakyThrows
	public R getH5WeixinAuthorizeUrl(@ApiParam("重定向地址") @RequestParam String redirectUri) {
		return R.data(weChatService.getWeiXinH5Oauth2AuthorizeUrl(MiniProgramType.OFFICIAL, redirectUri, ScopeTypeEnum.snsapi_userinfo));
	}

	/**
	 * 获取微信授权URL
	 */
	@GetMapping("/getWeiXinH5UserInfo")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "获取微信授权URL")
	public R getWeiXinH5UserInfo(@ApiParam("微信授权Code") @RequestParam String code) {
		String weiXinH5AccessToken = weChatService.getWeiXinH5AccessToken(MiniProgramType.OFFICIAL, code);
		if (StringUtils.isEmpty(weiXinH5AccessToken)) {
			return R.fail("获取用户信息失败");
		}
		JSONObject weiXinH5UserInfo = weChatService.getWeiXinH5UserInfo(weiXinH5AccessToken);
		if (ObjectUtils.isEmpty(weiXinH5UserInfo)) {
			return R.fail("获取用户信息失败");
		}
		LoginUser loginUser = new LoginUser() {{
			setOpenid(weiXinH5UserInfo.getString(BeanPropertyUtil.getFieldName(LoginUser::getOpenid).toLowerCase()));
			setNickName(weiXinH5UserInfo.getString(BeanPropertyUtil.getFieldName(LoginUser::getNickName).toLowerCase()));
			setAvatar(weiXinH5UserInfo.getString("headimgurl"));
			String sex = weiXinH5UserInfo.getString(BeanPropertyUtil.getFieldName(LoginUser::getSex).toLowerCase());
			switch (sex) {
				case "1":
					sex = "男";
					break;
				case "2":
					sex = "女";
					break;
				default:
					sex = "未知";
					break;
			}
			setSex(sex);
		}};
		return login(loginUser);
	}

	/**
	 * h5登录
	 */
	@PostMapping("/h5Login")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "h5登录", notes = "传入loginUser")
	public R h5Login(@RequestParam String phone, @RequestParam String code, @RequestParam String smsId) {
		Assert.isTrue(SmsUtil.validateMessage(SmsCodeEnum.VALIDATE.name(), smsId, code, phone), SmsUtil.VALIDATE_FAIL);
		synchronized (phone.intern()) {
			List<LoginUser> users = loginUserService.list(Condition.getQueryWrapper(new LoginUser()).lambda().eq(LoginUser::getPhone, phone).orderByDesc(LoginUser::getCreateTime));
			if (CollUtil.isEmpty(users)) {
				LoginUser user = new LoginUser();
				user.setPhone(phone);
				//给h5设置默认的头像和昵称
				user.setNickName(phone);
				user.setAvatar("https://vote-obs.guosen-fumao.cn/762a90334f9d46c49f99972a4967903e-unlogin.png");
				loginUserService.save(user);
				return R.data(user);
			}
			return R.data(users.get(0));
		}
	}


	/**
	 * 查询用户积分
	 */
	@PostMapping("/userPufaPoint")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "查询用户普法积分")
	public R<UserPufaPoint> userPufaPoint(@ApiParam(value = "用户手机号码", required = true) @RequestParam String phone) {
		return R.data(userPufaPointService.getOne(
			Wrappers.<UserPufaPoint>lambdaQuery()
				.eq(UserPufaPoint::getPhone, phone)));
	}

	/**
	 * 查询用户热力值
	 */
	@PostMapping("/userHeatValue")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "查询用户热力值")
	public R<UserHeat> userHeatValue(@ApiParam(value = "用户手机号码", required = true) @RequestParam String phone) {
		return R.data(userHeatService.getOne(
			Wrappers.<UserHeat>lambdaQuery()
				.eq(UserHeat::getPhone, phone)));
	}

	/**
	 * 查询参赛用户票数
	 */
	@PostMapping("/userVoteCount")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "查询参赛用户票数")
	public R<Long> userVoteCount(@ApiParam(value = "用户手机号码", required = true) @RequestParam String phone) {
		Map<String, Object> map = activeProductRecordService.getMap(Wrappers.<ActiveProductRecord>query().select(new StringBuilder("ifnull(sum(")
				.append(BeanPropertyUtil.getFieldNameToUnder(ActiveProductRecord::getVoteCount))
				.append("),0) as count")
				.toString())
			.lambda()
			.eq(ActiveProductRecord::getPhone, phone));
		return R.data(MapUtil.getLong(map, "count"));
	}

	/**
	 * 查询用户热力值和普法积分
	 */
	@GetMapping("/userHeatValueAndPufaPoint")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "查询用户热力值和普法积分")
	public R<Map<String, ?>> userHeatValueAndPufaPoint(@ApiParam(value = "用户手机号码", required = true) @RequestParam String phone) {
		Map<String, Object> hashMap = new HashMap<>();
		hashMap.put("userHeatValue", Optional.ofNullable(userHeatValue(phone).getData()).map(UserHeat::getHeatValue).orElse(BigDecimal.ZERO));
		hashMap.put("userPufaPoint", Optional.ofNullable(userPufaPoint(phone).getData()).map(UserPufaPoint::getPufaPoint).orElse(BigDecimal.ZERO));
		hashMap.put("userVoteCount", Optional.ofNullable(userVoteCount(phone).getData()).orElse(0L));
		return R.data(hashMap);
	}
}
