/*
 *      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.ldt.loginuser.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;

import javax.smartcardio.CardChannel;
import javax.validation.Valid;

import org.springblade.common.cache.CacheNames;
import org.springblade.common.constant.SystemConstant;
import org.springblade.common.enums.OrderType;
import org.springblade.common.enums.PayWay;
import org.springblade.common.utils.OtpUtils;
import org.springblade.core.cache.utils.CacheUtil;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.ldt.activityjoinrecord.service.IActivityJoinRecordService;
import org.springblade.modules.ldt.billrecord.entity.BillRecord;
import org.springblade.modules.ldt.billrecord.service.IBillRecordService;
import org.springblade.modules.ldt.channel.entity.PointChannel;
import org.springblade.modules.ldt.channel.service.IPointChannelService;
import org.springblade.modules.ldt.channeluserpoint.entity.ChannelUserPoint;
import org.springblade.modules.ldt.channeluserpoint.service.IChannelUserPointService;
import org.springblade.modules.ldt.loginuser.dto.LoginUserDTO;
import org.springblade.modules.ldt.loginuser.dto.PayDto;
import org.springblade.modules.ldt.mall.entity.Mall;
import org.springblade.modules.ldt.mall.service.IMallService;
import org.springblade.modules.ldt.member.entity.Member;
import org.springblade.modules.ldt.member.service.IMemberService;
import org.springblade.modules.ldt.pointdetail.entity.PointDetail;
import org.springblade.modules.ldt.pointdetail.service.IPointDetailService;
import org.springblade.modules.ldt.shop.entity.Shop;
import org.springblade.modules.ldt.shop.service.IShopService;
import org.springblade.modules.ldt.shopyingshou.entity.ShopYingshou;
import org.springblade.modules.ldt.shopyingshou.service.IShopYingshouService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestParam;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.modules.ldt.loginuser.entity.LoginUser;
import org.springblade.modules.ldt.loginuser.vo.LoginUserVO;
import org.springblade.modules.ldt.loginuser.service.ILoginUserService;
import org.springblade.core.boot.ctrl.BladeController;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 控制器
 *
 * @author BladeX
 * @since 2021-07-28
 */
@RestController
@AllArgsConstructor
@RequestMapping("cyzh-ldt/loginuser")
@Api(value = "", tags = "接口")
public class LoginUserController extends BladeController {

	private final ILoginUserService loginUserService;

	private final IShopService shopService;
	private final IBillRecordService billRecordService;

	private final static String USER_INFO = "userId:";
	private final RedisTemplate<String, String> redisTemplate;


	/**
	 * 详情
	 */
	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情", notes = "传入loginUser")
	public R<LoginUser> detail(LoginUser loginUser) {
		LoginUser detail = loginUserService.getOne(Condition.getQueryWrapper(loginUser));
		return R.data(detail);
	}

	/**
	 * 分页
	 */
	@GetMapping("/list")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "分页", notes = "传入loginUser")
	public R<IPage<LoginUser>> list(@RequestParam Map<String, Object> loginUser, Query query) {
		IPage<LoginUser> pages = loginUserService.page(Condition.getPage(query), Condition.getQueryWrapper(loginUser, LoginUser.class));
		return R.data(pages);
	}

	/**
	 * 自定义分页
	 */
	@GetMapping("/page")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "分页", notes = "传入loginUser")
	public R<IPage<LoginUserVO>> page(LoginUserVO loginUser, Query query) {
		IPage<LoginUserVO> pages = loginUserService.selectLoginUserPage(Condition.getPage(query), loginUser);
		return R.data(pages);
	}

	/**
	 * 新增
	 */
	@PostMapping("/save")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "新增", notes = "传入loginUser")
	public R save(@Valid @RequestBody LoginUser loginUser) {
		return R.status(loginUserService.save(loginUser));
	}

	/**
	 * 修改
	 */
	@PostMapping("/update")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "修改", notes = "传入loginUser")
	public R update(@Valid @RequestBody LoginUser loginUser) {
		return R.status(loginUserService.updateById(loginUser));
	}

	/**
	 * 新增或修改
	 */
	@PostMapping("/submit")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "新增或修改", notes = "传入loginUser")
	public R submit(@Valid @RequestBody LoginUser loginUser) {
		return R.status(loginUserService.saveOrUpdate(loginUser));
	}


	/**
	 * 删除
	 */
	@PostMapping("/remove")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "逻辑删除", notes = "传入ids")
	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
		return R.status(loginUserService.deleteLogic(Func.toLongList(ids)));
	}

	/**
	 * 登录
	 */
	@PostMapping("/login")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "登录", notes = "传入loginUser")
	public R login(@RequestBody LoginUserDTO loginUserDTO) {
		return R.data(loginUserService.login(loginUserDTO));
	}

	/**
	 * 用户扫码支付生成预订单
	 */
	@PostMapping("/payBefore")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "用户扫码支付", notes = "传入loginUser")
	public R<BillRecord> payBefore(@RequestBody PayDto payDto) {
		if (payDto.getSecret() != null) {
			String id = OtpUtils.getIdFormCode(payDto.getSecret());
			boolean validate = OtpUtils.validate(id, payDto.getSecret());
			if (validate) {

			} else {
//				Assert.isTrue(false,"用户授权无效");
			}
			payDto.setLoginUserId(Long.valueOf(id));

		}
		Assert.notNull(payDto.getLoginUserId(), "用户信息不能为空");
		Assert.notNull(payDto.getMoney(), "商品价格不能为空");
		Assert.notNull(payDto.getShopId(), "商店信息不能为空");
		Shop shop = shopService.getById(payDto.getShopId());
		Assert.notNull(shop, "商店信息不存在");
		LoginUser loginUser = loginUserService.getById(payDto.getLoginUserId());
		Assert.notNull(loginUser, "用户信息不存在");
		BillRecord billRecord = this.loginUserService.payBefore(loginUser, shop, payDto);
		if (payDto.getType() != null && 2 == payDto.getType()) {//商户扫用户付款码需要存缓存
			redisTemplate.opsForValue().set(CacheNames.SHOPSCANUSER + "::" + USER_INFO + payDto.getLoginUserId(), JSON.toJSONString(billRecord), 5, TimeUnit.MINUTES);
		}
		return R.data(billRecord);
	}

	/**
	 * 非平台用户扫码支付生成预订单-直接用微信原生的扫一扫支付，没有userId
	 */
	@PostMapping("/payBeforeForNormal")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "非平台用户扫码支付生成预订单", notes = "传入loginUser")
	public R<BillRecord> payBeforeForNormal(@RequestBody PayDto payDto) {

		Assert.notNull(payDto.getMoney(), "商品价格不能为空");
		Assert.notNull(payDto.getShopId(), "商店信息不能为空");
		Shop shop = shopService.getById(payDto.getShopId());
		Assert.notNull(shop, "商店信息不存在");

		//该记录没有用户信息
		BillRecord billRecord = new BillRecord();
		billRecord.setShopId(shop.getId());
		billRecord.setPrice(payDto.getMoney());
		billRecord.setRealPayAmount(payDto.getMoney());
		billRecord.setPayWay(PayWay.CASH.getName());
		billRecord.setPayAmount(payDto.getMoney().toString());
		billRecord.setPayStatus(SystemConstant.BillRecordPayStatus.PAYING.getValue());
		billRecord.setBillsTitle(payDto.getBillsTitle());
		billRecord.setExpireTime(payDto.getExpireTime());
		billRecord.setType(OrderType.USER_PAY.getName());
		billRecord.setMallId(shop.getMallId());
		billRecord.setBillsDesc(payDto.getBillsTitle());
		billRecordService.save(billRecord);
		return R.data(billRecord);
	}

	/**
	 * 商家扫用户付款码时用户端轮询redis中的订单信息
	 */
	@GetMapping("/getBillrecordFromRedis")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "用户扫码支付", notes = "传入loginUser")
	public R<BillRecord> payBefore(BillRecord billRecord) {
		String s = redisTemplate.opsForValue().get(CacheNames.SHOPSCANUSER + "::" + USER_INFO + billRecord.getUserId());
		if (s != null) {
			JSONObject billRecord1 = JSON.parseObject(s);
			return R.data(billRecord1.toJavaObject(BillRecord.class));
		}

		return R.data(null);
	}

	/**
	 * 清除缓存
	 */
	@GetMapping("/clearBillRecordCache")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "清除缓存", notes = "传入loginUser")
	public R clearBillRecordCache(BillRecord billRecord) {

		return R.data(redisTemplate.delete(CacheNames.SHOPSCANUSER + "::" + USER_INFO + billRecord.getUserId()));
	}

	private final IPointDetailService pointDetailService;
	private final IPointChannelService pointChannelService;
	private final IChannelUserPointService channelUserPointService;
	private final IMallService mallService;
	private final IMemberService memberService;
	private final IShopYingshouService shopYingshouService;
	/**
	 * /**
	 * * 清除缓存
	 */
	@PostMapping("/moniCallBack")
	@ApiOperationSupport(order = 8)
	@ApiOperation(value = "模拟回调", notes = "传入loginUser")
	public R moniCallBack(@RequestBody BillRecord params) {
		BillRecord billRecord = billRecordService.getById(params.getId());
		if(billRecord ==null ){
//			bladeLogger.error("第三方支付返回的订单不存在",successParams.toString());
		}else{

			Shop shop = shopService.getById(billRecord.getShopId());

			if(SystemConstant.BillRecordPayStatus.PAYING.getValue() == billRecord.getPayStatus()){//只处理待支付订单变成已支付成功的情况

				if(billRecord.getUserId() == null){//非平台用户支付直接增加用户可提现余额，无需赠送积分
					billRecord.setPayStatus(SystemConstant.BillRecordPayStatus.PAYED.getValue());
					billRecordService.updateById(billRecord);
					shop.setWithdrawTotalPrice(shop.getWithdrawTotalPrice() != null ?
						shop.getWithdrawTotalPrice().add(billRecord.getRealPayAmount()) : billRecord.getRealPayAmount());
					shopService.updateById(shop);
					return R.data(true);
				}

				/**                  平台用户支付回调                 **/
				//增加商户的可提现余额
				shop.setWithdrawTotalPrice(shop.getWithdrawTotalPrice().add(billRecord.getRealPayAmount()));
				shop.setSales(shop.getSales() != null?shop.getSales()+1:1);
				shop.setTradeTimes(shop.getTradeTimes() != null ? shop.getTradeTimes() +1 : 1);
				shopService.updateById(shop);
				//支付成功增加商场和商家的积分成本，增加用户的可用积分余额

				//查询是否有商场送积分的待确认记录
				List<PointDetail> mallPointDetails = pointDetailService.getBaseMapper().selectList(new QueryWrapper<>(new PointDetail()).lambda()
					.eq(PointDetail::getBillRecordId,billRecord.getId())
					.eq(PointDetail::getType,SystemConstant.PointDetailType.MALL_SEND.getValue()).orderByDesc(PointDetail::getCreateTime));
				if (mallPointDetails.size() > 0) {
					PointDetail mallPointDetail = mallPointDetails.get(0);
					/**
					 * 增加商场的积分成本
					 */
					mallPointDetail.setBillRecordStatus(SystemConstant.BillRecordPayStatus.PAYED.getValue());
					pointDetailService.updateById(mallPointDetail);
					//获取商场的积分渠道
					PointChannel pointChannel = pointChannelService.getBaseMapper().selectOne(new QueryWrapper<>(new PointChannel()).lambda()
						.eq(PointChannel::getType,SystemConstant.PointChannelType.MALL.getValue())
						.eq(PointChannel::getRelationId,billRecord.getMallId()));
					//获取该用户在商场渠道的积分信息
					ChannelUserPoint channelUserPoint = channelUserPointService.getBaseMapper().selectOne(new QueryWrapper<>(new ChannelUserPoint()).lambda()
						.eq(ChannelUserPoint::getUserId, billRecord.getUserId())
						.eq(ChannelUserPoint::getChannelId, pointChannel.getId()));
					//新增该用户在该商场的积分信息
					channelUserPoint.setUsablePoint(channelUserPoint.getUsablePoint().add(mallPointDetail.getPoint()));
					channelUserPoint.setTotalPoint(channelUserPoint.getTotalPoint().add(mallPointDetail.getPoint()));
					channelUserPoint.setUsablePointValue(channelUserPoint.getUsablePoint().multiply(pointChannel.getPointValue()).divide(BigDecimal.valueOf(100)));
					channelUserPointService.updateById(channelUserPoint);
					//增加该商场的积分总价值
					Mall mall = mallService.getById(billRecord.getMallId());

					mall.setTotalPointValue(mall.getTotalPointValue() != null?mall.getTotalPointValue().add(mallPointDetail.getPointValue()):mallPointDetail.getPointValue());
					mallService.updateById(mall);
					//增加会员的可用积分
					Member mallMember = memberService.getBaseMapper().selectOne(new QueryWrapper<>(new Member()).lambda()
						.eq(Member::getType,SystemConstant.MALLORSHOP.MALL.getValue())
						.eq(Member::getUserId,billRecord.getUserId())
						.eq(Member::getMallId,billRecord.getMallId()));
					mallMember.setPointTotal(mallMember.getPointTotal() != null?mallMember.getPointTotal().add(mallPointDetail.getPoint()) :mallPointDetail.getPoint());
					mallMember.setPointValue(mallMember.getPointValue() != null?mallMember.getPointValue().add(mallPointDetail.getPointValue()):mallPointDetail.getPointValue());
					memberService.updateById(mallMember);
				}

				/**
				 * 商场送积分的待确认记录
				 */
				List<PointDetail> shopPointDetails = pointDetailService.getBaseMapper().selectList(new QueryWrapper<>(new PointDetail()).lambda()
					.eq(PointDetail::getBillRecordId,billRecord.getId())
					.eq(PointDetail::getType,SystemConstant.PointDetailType.SHOP_SEND.getValue()).orderByDesc(PointDetail::getCreateTime));
				if(shopPointDetails.size()>0){
					PointDetail shopPointDetail = shopPointDetails.get(0);

					//增加商家的积分成本
					shop.setTotalPointValue(shop.getTotalPointValue() != null ? shop.getTotalPointValue().add(shopPointDetail.getPointValue()):shopPointDetail.getPointValue());
					shopService.updateById(shop);
					shopPointDetail.setBillRecordStatus(SystemConstant.BillRecordPayStatus.PAYED.getValue());
					pointDetailService.updateById(shopPointDetail);
					//增加该商店会员的可用积分
					Member shopMember = memberService.getBaseMapper().selectOne(new QueryWrapper<>(new Member()).lambda()
						.eq(Member::getUserId,billRecord.getUserId())
						.eq(Member::getType,SystemConstant.MALLORSHOP.SHOP.getValue())
						.eq(Member::getShopId,billRecord.getShopId()));
					shopMember.setPointValue(shopMember.getPointValue() != null ? shopMember.getPointValue().add(shopPointDetail.getPointValue()): shopPointDetail.getPointValue());
					shopMember.setPointTotal(shopMember.getPointTotal() != null ? shopMember.getPointTotal().add(shopPointDetail.getPoint()): shopPointDetail.getPoint());
					memberService.updateById(shopMember);

				}

				/**   判断是否有商家待应收记录   **/
				ShopYingshou shopYingshou = shopYingshouService.getBaseMapper().selectOne(new QueryWrapper<>(new ShopYingshou()).lambda()
					.eq(ShopYingshou::getBillRecordStatus, SystemConstant.BillRecordPayStatus.PAYING.getValue())
					.eq(ShopYingshou::getBillRecordId, billRecord.getId()));
				if(shopYingshou != null){
					//增加商户的总应收
					shopYingshou.setBillRecordStatus(SystemConstant.BillRecordPayStatus.PAYED.getValue());
					shop.setTotalFunkPrice(shop.getTotalFunkPrice() != null? shop.getTotalFunkPrice().add(shopYingshou.getPointValue()):shopYingshou.getPointValue());
					shopService.updateById(shop);
				}
				//修改订单状态
				billRecord.setPayStatus(SystemConstant.BillRecordPayStatus.PAYED.getValue());
				billRecordService.updateById(billRecord);

			}
		}
		return R.data(true);
	}


}
