package org.springblade.gateway.shop_gateway.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springblade.common.enums.AppConstant;
import org.springblade.common.enums.CsFlag;
import org.springblade.common.enums.WithdrawType;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.support.Kv;
import org.springblade.gateway.shop_gateway.entity.dto.ShopAuditDto;
import org.springblade.gateway.shop_gateway.entity.vo.BalanceAccountInfoVO;
import org.springblade.gateway.shop_gateway.entity.vo.IndexVO;
import org.springblade.gateway.shop_gateway.entity.vo.MemberInfoVO;
import org.springblade.gateway.shop_gateway.entity.vo.ShopBillsInfoVO;
import org.springblade.gateway.shop_gateway.service.IAppShopService;
import org.springblade.ldt.bills.entity.Bills;
import org.springblade.ldt.bills.entity.WithdrawRec;
import org.springblade.ldt.bills.service.IBillsService;
import org.springblade.ldt.notice.entity.NoticeManagementContent;
import org.springblade.ldt.notice.service.INoticeManagementContentService;
import org.springblade.ldt.notice.wrapper.NoticeManagementContentWrapper;
import org.springblade.ldt.shop.entity.Shop;
import org.springblade.ldt.shop.service.IShopService;
import org.springblade.ldt.shop.vo.ShopVO;
import org.springblade.ldt.shop.wrapper.ShopWrapper;
import org.springblade.ldt.user.entity.Member;
import org.springblade.ldt.user.service.IMemberService;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserInfo;
import org.springblade.modules.system.service.impl.UserServiceImpl;
import org.springblade.yeePay.common.YeepayApiConstant;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author cy-computer
 */
@RestController
@RequestMapping("/shop")
@Api(tags = "商户控制层")
@AllArgsConstructor
public class AppShopController {

	private IAppShopService appShopService;
	private IMemberService memberService;
	private IShopService shopService;
	private IBillsService billsService;
	private UserServiceImpl userService;
	private INoticeManagementContentService noticeManagementContentService;

	/**
	 * 分页
	 */
	@GetMapping("/list")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "分页", notes = "传入shop")
	public R<IPage<ShopVO>> list(@RequestParam Map<String, Object> shop, Query query) {
		String filter = (String) shop.get("filter");
		shop.remove("filter");
		IPage<Shop> pages = shopService.page(Condition.getPage(query), Condition.getQueryWrapper(shop, Shop.class).lambda()
			.orderByDesc("score".equals(filter), Shop::getScore)
			.orderByDesc("sales".equals(filter), Shop::getSales)
			.orderByDesc(Shop::getCreateTime));
		return R.data(ShopWrapper.build().pageVO(pages));
	}


	/**
	 * 商户端获取我的商户列表
	 */
	@GetMapping("/myShop")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "商户端获取我的商户列表", notes = "shop")
	@TenantIgnore
	public R myShop(Shop shop) {
		List<Shop> list = shopService.list(Condition.getQueryWrapper(shop));
		if (CollUtil.isEmpty(list)) {
			return R.data(list);
		}
		List<ShopVO> resList = new ArrayList();
		for (Shop item : list) {
			ShopVO shopVO = new ShopVO();
			BeanUtil.copyProperties(item,shopVO);
			Kv tokenInfo = this.getRefreshToken(item);
			shopVO.setTokenInfo(tokenInfo);
			resList.add(shopVO);
		}
		return R.data(resList);
	}

	/**
	 *根据tenantId获取对应refresh_token信息
	 */
	private Kv getRefreshToken(Shop shop){
		User user = userService.getBaseMapper().selectOne(new QueryWrapper<User>().lambda().eq(User::getTenantId, shop.getTenantId()).orderByAsc(User::getCreateTime).last("limit 1"));
		UserInfo userInfo = userService.buildUserInfo(user);
		Kv authInfo = TokenUtil.createAuthInfo(userInfo);
		authInfo.put("shop", shop);
		return authInfo;
	}

	@PostMapping("submitAudit")
	@ApiOperation(value = "商户提交审核")
	public R submitAudit(@RequestBody ShopAuditDto shopAuditDto) {
		appShopService.submitAudit(shopAuditDto);
		return R.success("提交成功");
	}


	@PostMapping("userBalanceWithdraw")
	@ApiOperation(value = "用户余额提现（结算）")
	public R userBalanceWithdraw(@RequestBody WithdrawRec withdrawRec) {
		withdrawRec.setType(WithdrawType.BALANCE_WITHDRAW);
		withdrawRec.setReceiveType(YeepayApiConstant.receiveType.REAL_TIME.name());
		return R.data(appShopService.userBalanceWithdraw(withdrawRec));
	}

	@PostMapping("userPointWithdraw")
	@ApiOperation(value = "用户积分提现")
	public R userPointWithdraw(@RequestBody WithdrawRec withdrawRec) {
		withdrawRec.setType(WithdrawType.POINT_WITHDRAW);
		withdrawRec.setReceiveType(YeepayApiConstant.receiveType.REAL_TIME.name());
		return R.data(appShopService.userPointWithdraw(withdrawRec));
	}

	@GetMapping("indexInfo")
	@ApiOperation(value = "首页数据")
	public R indexInfo(@RequestParam(value = "shopId") Long shopId) {

		//今日新增会员数
		int newMembers = memberService.getBaseMapper().selectCount(new QueryWrapper<Member>()
			.lambda()
			.eq(Member::getShopId, shopId)
			.ge(Member::getCreateTime, DateUtil.beginOfDay(new Date()))
			.le(Member::getCreateTime, DateUtil.endOfDay(new Date()))
		);
		//店铺会员总数
		int allMembers = getTotalMembers(shopId);

		BalanceAccountInfoVO balanceAccountInfoVO = appShopService.queryBalance(shopId);
		//店铺总收益
		Shop shop = shopService.getById(shopId);
		//店铺总收益=现金收益+未核销的渠道积分+已核销的渠道积分+总余额收益
		BigDecimal totalValue = shop.getTotalBalance().add(shop.getCharge()).add(shop.getWithdrawCharge()).add(shop.getTotalPoint());

		//积分总价值
		BigDecimal pointsTotalValue = shop.getTotalValue();


		//交易笔数
		int transactionNum = billsService.count(Condition.getQueryWrapper(new Bills()).lambda()
			.eq(Bills::getReceiveId, shopId)
			.and(wrapper -> wrapper
				.eq(Bills::getPayStatus, AppConstant.BillPayStatus.付款成功.name())
				.or()
				.eq(Bills::getCsFlag, CsFlag.CHECK)));


		//今日现金收益
		BigDecimal todayBalance = Convert.toBigDecimal(balanceAccountInfoVO.getTodayNum());
		//今日积分收益
		BigDecimal todayPoint = this.getTodayPoint(shopId);
		//渠道积分今日收益
		BigDecimal todayChannel = this.getTodayCharge(shopId);
		//今日营收
		BigDecimal todayCharge = BigDecimal.ZERO.add(todayBalance).add(todayPoint).add(todayChannel);

		return R.data(
			IndexVO.builder()
				.totalValue(totalValue)
				.todayCharge(todayCharge)
				.allMembers(allMembers)
				.pointsTotalValue(pointsTotalValue)
				.transactionNum(transactionNum)
				.newMember(newMembers)
				.build()
		);
	}

	@GetMapping("memberInfo")
	@ApiOperation(value = "会员中心数据")
	public R memberInfo(@RequestParam(value = "shopId") Long shopId) {

		//店铺会员总数
		int allMembers = getTotalMembers(shopId);

		Shop shop = shopService.getById(shopId);

		return R.data(MemberInfoVO
			.builder()
			.totalPointValue(shop.getTotalValue())
			.pointUnitValue(shop.getPointRate())
			.sendPointUnit(shop.getSendPointUnit())
			.memberNum(allMembers)
			.isOpenMember(shop.getIsOpenMember())
			.build());
	}

	@GetMapping("shopBillsInfo")
	@ApiOperation(value = "店铺账单详情")
	public R shopBillsInfo(@RequestParam(value = "shopId") Long shopId) {
		/***
		 * bill表的price表示用现金支付的，而shop表的balance表示的是可提现的现金
		 * bill表的balance_num表示用户用积分余额支付的，而shop表的point表示的是可提现的积分余额
		 * bill表的point_num表示用户用渠道积分支付的，而shop表的charge表示总应收的渠道积分
		 */
		Shop shop = shopService.getById(shopId);
		Assert.notNull(shop, "找不到该商户");

		BalanceAccountInfoVO balanceAccountInfoVO = appShopService.queryBalance(shopId);

		//今日现金收益
		BigDecimal todayBalance = Convert.toBigDecimal(balanceAccountInfoVO.getTodayNum());

		//今日积分收益
		BigDecimal todayPoint = this.getTodayPoint(shopId);

		//渠道积分今日收益
		BigDecimal todayCharge = this.getTodayCharge(shopId);

		//今日总收益[今日现金收益，余额收益，渠道积分收益]
		BigDecimal todayRevenue = BigDecimal.ZERO.add(todayBalance).add(todayPoint).add(todayCharge);

		//总渠道积分收益=未核销的渠道积分 + 已核销的渠道积分
		BigDecimal totalCharge = Optional.ofNullable(shop.getCharge()).orElse(BigDecimal.ZERO).add(shop.getWithdrawCharge());
		//总收益
		BigDecimal totalRevenue = Optional.ofNullable(shop.getTotalBalance()).orElse(BigDecimal.ZERO).add(shop.getTotalPoint()).add(totalCharge);
		//总资产 = 可提现余额 + 未核销积分 + 可提现积分
		BigDecimal availableNum = Convert.toBigDecimal(balanceAccountInfoVO.getAvailableNum());
		BigDecimal totalAssets = availableNum.add(shop.getCharge()).add(shop.getPoint());

		ShopBillsInfoVO shopBillsInfoVO = ShopBillsInfoVO
			.builder()
			//后端null值返回到前端却是-1
			.balance(availableNum)
			.totalBalance(Convert.toBigDecimal(balanceAccountInfoVO.getTotalNum()))
			.todayBalance(Optional.ofNullable(todayBalance).orElse(BigDecimal.ZERO))
			.point(Optional.ofNullable(shop.getPoint()).orElse(BigDecimal.ZERO))
			.totalPoint(Optional.ofNullable(shop.getTotalPoint()).orElse(BigDecimal.ZERO))
			.todayPoint(Optional.ofNullable(todayPoint).orElse(BigDecimal.ZERO))
			.charge(Optional.ofNullable(shop.getCharge()).orElse(BigDecimal.ZERO))
			.totalCharge(Optional.ofNullable(totalCharge).orElse(BigDecimal.ZERO))
			.todayCharge(Optional.ofNullable(todayCharge).orElse(BigDecimal.ZERO))
			.todayRevenue(todayRevenue)
			.totalAssets(totalAssets)
			.totalRevenue(totalRevenue)
			.build();
		return R.data(shopBillsInfoVO);
	}

	private int getTotalMembers(Long shopId) {
		return memberService.getBaseMapper().selectCount(new QueryWrapper<Member>().lambda().eq(Member::getShopId, shopId));
	}

	private BigDecimal todayRevenue(Long shopId) {
		//今日营收
		QueryWrapper<Bills> queryWrapper = new QueryWrapper<>(new Bills());
		queryWrapper.select("IFNULL(sum(cost),0) as todayRevenue")
			.lambda()
			.eq(Bills::getReceiveId, shopId)
			.ge(Bills::getCreateTime, DateUtil.beginOfDay(new Date()))
			.le(Bills::getCreateTime, DateUtil.endOfDay(new Date()))
			.and(wrapper -> wrapper
				.eq(Bills::getPayStatus, AppConstant.BillPayStatus.付款成功.name())
				.or()
				.eq(Bills::getCsFlag, CsFlag.CHECK));
		Map<String, Object> map = billsService.getMap(queryWrapper);
		BigDecimal todayRevenue = (BigDecimal) map.get("todayRevenue");
		return todayRevenue;
	}

	/**
	 * 获取今日现金收益
	 *
	 * @param shopId
	 * @return
	 */
	private BigDecimal getTodayBalance(Long shopId) {
		QueryWrapper<Bills> queryWrapper = new QueryWrapper<>();
		queryWrapper.select("IFNULL(sum(receive_num_yp),0) as todayBalance")
			.lambda()
			.eq(Bills::getReceiveId, shopId)
			.between(Bills::getCreateTime, DateUtil.beginOfDay(new Date()), DateUtil.endOfDay(new Date()))
			.and(wrapper -> wrapper
				.eq(Bills::getPayStatus, AppConstant.BillPayStatus.付款成功.name())
				.or()
				.eq(Bills::getCsFlag, CsFlag.CHECK));
		Map<String, Object> map = billsService.getMap(queryWrapper);
		BigDecimal todayBalance = (BigDecimal) map.get("todayBalance");
		return todayBalance;
	}

	/**
	 * 获取今日积分收益
	 *
	 * @param shopId
	 * @return
	 */
	private BigDecimal getTodayPoint(Long shopId) {
		QueryWrapper<Bills> queryWrapper2 = new QueryWrapper<>();
		queryWrapper2.select("IFNULL(sum(balance_num),0) as todayPoint")
			.lambda()
			.eq(Bills::getReceiveId, shopId)
			.between(Bills::getCreateTime, DateUtil.beginOfDay(new Date()), DateUtil.endOfDay(new Date()))
			.and(wrapper -> wrapper
				.eq(Bills::getPayStatus, AppConstant.BillPayStatus.付款成功.name())
				.or()
				.eq(Bills::getCsFlag, CsFlag.CHECK));
		Map<String, Object> map2 = billsService.getMap(queryWrapper2);
		BigDecimal todayPoint = map2 == null ? BigDecimal.ZERO : (BigDecimal) map2.get("todayPoint");
		return todayPoint;
	}

	/**
	 * 获取今日渠道积分收益
	 *
	 * @param shopId
	 * @return
	 */
	private BigDecimal getTodayCharge(Long shopId) {
		QueryWrapper<Bills> queryWrapper3 = new QueryWrapper<>();
		queryWrapper3.select("IFNULL(sum(point_num),0) as todayCharge")
			.lambda()
			.eq(Bills::getReceiveId, shopId)
			.between(Bills::getCreateTime, DateUtil.beginOfDay(new Date()), DateUtil.endOfDay(new Date()))
			.and(wrapper -> wrapper
				.eq(Bills::getPayStatus, AppConstant.BillPayStatus.付款成功.name())
				.or()
				.eq(Bills::getCsFlag, CsFlag.CHECK));
		Map<String, Object> map3 = billsService.getMap(queryWrapper3);
		BigDecimal todayCharge = map3 == null ? BigDecimal.ZERO : (BigDecimal) map3.get("todayCharge");
		return todayCharge;
	}

	@GetMapping("configApp")
	@ApiOperation(value = "测试公众号配置")
	public R configApp(@RequestParam(value = "shopId") Long shopId) {
		return appShopService.configApp(shopService.getById(shopId));
	}

	@PostMapping("submitNotice")
	@ApiOperation(value = "商户创建公告信息")
	public R submitAudit(@RequestBody NoticeManagementContent noticeContent) {
		return R.status(appShopService.submitNotice(noticeContent));
	}
	/**
	 * 获取发布的公告列表
	 */
	@GetMapping("/getPublishNoticeList")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "获取发布的公告列表", notes = "传入notice")
	public R getPublishNoticeList(NoticeManagementContent noticeManagementContent, Query query) {
		IPage<NoticeManagementContent> pages = noticeManagementContentService.page(Condition.getPage(query), Condition.getQueryWrapper(noticeManagementContent).lambda()
			.orderByDesc(NoticeManagementContent::getCreateTime));
		return R.data(NoticeManagementContentWrapper.build().pageVO(pages));
	}

}
