/*
 *      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.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.response.AlipayTradePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.common.constant.CommonConstant;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.exception.ServiceException;
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.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.modules.api.request.ConsignPayRequest;
import org.springblade.modules.api.request.OrderCommonSaveRequest;
import org.springblade.modules.api.request.OrderConsignRandomRequest;
import org.springblade.modules.api.request.OrderTakeRequest;
import org.springblade.modules.api.response.ConsignResponse;
import org.springblade.modules.api.service.ITradeService;
import org.springblade.modules.auth.utils.TokenUtil;
import org.springblade.modules.finance.entity.Order;
import org.springblade.modules.finance.entity.OrderConsign;
import org.springblade.modules.finance.entity.OrderGrant;
import org.springblade.modules.finance.entity.PlatformAuthorization;
import org.springblade.modules.finance.mapper.PlatformAuthorizationMapper;
import org.springblade.modules.finance.pay.entity.AlipayProperties;
import org.springblade.modules.finance.service.IOrderConsignService;
import org.springblade.modules.finance.service.IOrderGrantService;
import org.springblade.modules.finance.service.IOrderService;
import org.springblade.modules.finance.vo.OrderVO;
import org.springblade.modules.finance.wrapper.OrderWrapper;
import org.springblade.modules.shopping.entity.Consign;
import org.springblade.modules.shopping.service.IConsignService;
import org.springblade.modules.shopping.vo.ConsignListVO;
import org.springblade.modules.shopping.vo.ConsignVO;
import org.springblade.modules.shopping.wrapper.ConsignWrapper;
import org.springblade.modules.system.entity.User;
import org.springblade.modules.system.entity.UserApp;
import org.springblade.modules.system.mapper.UserAppMapper;
import org.springblade.modules.system.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 控制器
 *
 * @author xuwei
 * @since 2021-12-23
 */
@RestController
@AllArgsConstructor
@RequestMapping(CommonConstant.API_URL)
@Api(value = "订单模块", tags = "05.订单模块")
public class Api05Controller extends BladeController {

	private static final Logger log = LoggerFactory.getLogger(Api05Controller.class);

	private final IOrderService orderService;
	private final IConsignService consignService;
	private final IOrderConsignService orderConsignService;
	private final IOrderGrantService orderGrantService;

	@Resource
	private ITradeService iTradeService;

	@Resource
	private PlatformAuthorizationMapper paMapper;

	@Resource
	private UserAppMapper userAppMapper;

	@Resource
	private IUserService userService;

	//抢购
	private static final String TRADE_URL = "/api/v1/aliPay/sdk/trade_notify_url";
	@Autowired
	private AlipayClient client;//支付宝请求sdk客户端

	@Autowired
	private AlipayProperties properties;//支付宝sdk配置

	@PostMapping("/finance/order-commonSave")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "购买商品", notes = "传入用户ID")
	public R orderCommonSave(@Valid @RequestBody OrderCommonSaveRequest request) {
		//租户号
		String tenantId = WebUtil.getRequest().getHeader(TokenUtil.TENANT_HEADER_KEY);
		if(StringUtil.isEmpty(request.getDistributeMode())){
			request.setDistributeMode(2); //物流配送
		}
		if(StringUtil.isEmpty(request.getUserId())){
			return R.fail("请求参数错误！");
		}
		if(request.getGoodsList() == null || request.getGoodsList().size() == 0){
			return R.fail("请选择购买的商品！");
		}
		return R.data(orderService.commonOrderInsert(request, tenantId));
	}

	@PostMapping("/finance/order-consignRandom")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "寄售抢购", notes = "抢购订单")
	@Transactional(rollbackFor = Exception.class)
	public R consignRandom(@RequestBody OrderConsignRandomRequest request) {
		String tenantId = WebUtil.getRequest().getHeader(TokenUtil.TENANT_HEADER_KEY);
		UserApp userApp = new UserApp();
		UserApp query = userApp.selectOne(Wrappers.<UserApp>lambdaQuery().eq(UserApp::getUserId,request.getUserId()));
		if (query == null){
			return R.fail("该用户不存在");
		}
		if (query.getState() != 1){
			return R.fail("登录账号已冻结");
		}
		if (query.getCreditScore() < 100){
			return R.fail("您的信誉分不够");
		}
		if (StringUtil.isEmpty(query.getAlipayUserId())) {
			return R.fail("请绑定支付宝打款账号");
		}
		if (query.getTicket() < 100){
			throw new ServiceException("您的绿色积分达不到要求！");
		}
		//判断用户授权
		ConsignResponse response = orderService.consignGrant(query, request.getConsignConfigId(), request.getOrderNo());
		if (response.getStatus() == 2){
			//已授权则生成订单
			String outTradeNo = orderService.consignOrderInsert(request, query, tenantId);
			if (!StringUtil.isEmpty(outTradeNo)){
				//通过订单号获取授权信息
				OrderGrant orderGrant = orderGrantService.getOne(Wrappers.<OrderGrant>lambdaQuery().eq(OrderGrant::getOrderNo, request.getOrderNo()));
				//重新查询返回是否授权
				response = orderService.consignGrant(query, request.getConsignConfigId(), request.getOrderNo());
				//返回订单号
				response.setOutTradeNo(outTradeNo);
				//获取当前订单信息
				OrderConsign orderConsign = orderConsignService.getOne(Wrappers.lambdaQuery(OrderConsign.class).eq(OrderConsign::getOutTradeNo,outTradeNo));

				//查询寄售商品
				Consign consign = consignService.getById(orderConsign.getConsignId());
				//收款金额 默认等于抢购金额
				BigDecimal collectionPrice = new BigDecimal(consign.getConsignPrice());

				//使用收款账户进行打款
				boolean flg = orderConsign(outTradeNo, request.getOrderNo(), collectionPrice.doubleValue());
				if (flg){//是否发起统一收单
					//修改授权状态
					flg = orderGrantService.thaw(orderGrant);//flg = true
					if (!flg){
						log.info("授权授权信息修改失败");
						throw new ServiceException("亲！请重新抢单");
					}
					return R.data(response);
				}

				throw new ServiceException("亲！请重新抢单");
			}
		}
		//判断用户授权
		return R.data(response);
	}

	@PostMapping("checkConsignPay")
	@ApiOperation(value = "确认付款id")
	public R checkConsignPay(@RequestBody ConsignPayRequest payRequest){
		if(ObjectUtil.isNull(payRequest)){
			return R.fail("参数传递为null");
		}
		if(payRequest.getConsignId().size() < 1){
			return R.fail("请选择打款订单");
		}
		if(0 == payRequest.getPayType()){//等于0时进行打款操作
			List<Consign> consigns = consignService.listByIds(payRequest.getConsignId());
			for (Consign consign : consigns) {
				if(consign.getConsignState() == 2 && consign.getConsignFor() == 2){
					UserApp userApp = userAppMapper.selectOne(Wrappers.lambdaQuery(UserApp.class).eq(UserApp::getUserId,consign.getConsignUserId()));
					iTradeService.transfer(userApp, consign.getConsignPrice().toString(), consign.getConsignConfigId(),consign);
				}
			}
			return R.success("确认付款成功");
		} else {
			return R.fail("当前不支持特殊用户打款");
		}
	}

	/**
	 *
	 * @return
	 */
	@PostMapping("getConsignListByConfigId")
	@ApiOperation(value = "查询场次付款记录")
	public R<List<Consign>> getConsignListByConfigId(@ApiParam(value = "批次ID", required = true) @RequestParam Long consignConfigId){
		LambdaQueryWrapper<Consign> query = Wrappers.lambdaQuery(Consign.class);
		query.eq(Consign::getConsignConfigId,consignConfigId);
		query.eq(Consign::getConsignState, 2);
		query.eq(Consign::getNowStock, 0);
		query.eq(Consign::getConsignFor, 2);
		query.orderByDesc(Consign::getEndTime);
		List<Consign> list = consignService.list(query);
		//获取用户id
		List<Long> collect = list.stream().map(Consign::getConsignUserId).collect(Collectors.toList());
		List<User> users = userService.listByIds(collect);
		for (Consign consign : list) {
			List<User> first = users.stream().filter(s -> s.getId().equals(consign.getConsignUserId())).collect(Collectors.toList());
			if (CollUtil.isNotEmpty(first)) {
				User user = first.get(0);
				consign.setConsignUserName(user.getRealName());
				consign.setConsignUserPhone(user.getPhone());
			}
		}
		return R.data(list);
	}

	/**
	 *
	 * @return
	 */
	@PostMapping("getConsignALLList")
	@ApiOperation(value = "查询付款授权场次")
	public R<List<ConsignListVO>> getConsignALLList(){
		//查询已授权表记录
		LambdaQueryWrapper<PlatformAuthorization> query = Wrappers.lambdaQuery(PlatformAuthorization.class);
		query.eq(PlatformAuthorization::getState, 1);
		List<PlatformAuthorization> platformAuthorizations = paMapper.selectList(query);
		LambdaQueryWrapper<Consign> consignLambdaQueryWrapper = Wrappers.lambdaQuery(Consign.class);
		consignLambdaQueryWrapper.eq(Consign::getNowStock, 0).eq(Consign::getConsignState, 2).orderByDesc(Consign::getEndTime);
		List<Consign> list = consignService.list(consignLambdaQueryWrapper);
		ConsignListVO consignListVO = null;
		List<ConsignListVO> consignListVOS = new ArrayList<>();
		Map<Long, List<Consign>> collect1 = list.stream().collect(Collectors.groupingBy(Consign::getConsignConfigId));
		for (Map.Entry<Long, List<Consign>> entry : collect1.entrySet()) {
			consignListVO = new ConsignListVO();
			Integer num = entry.getValue().size();
			if(num > 0){
				consignListVO.setConsignConfigId(entry.getKey());
				consignListVO.setOrderNum(num);
				consignListVO.setOrderPrice(new BigDecimal(entry.getValue().get(0).getConsignPrice()).setScale(2, BigDecimal.ROUND_DOWN));
				consignListVO.setEndTime(entry.getValue().get(0).getEndTime());
				consignListVOS.add(consignListVO);
			}
		}
		return R.data(consignListVOS);
	}


	/**
	 *
	 * @return
	 */
	@PostMapping("getConsignList")
	@ApiOperation(value = "查询付款授权场次")
	public R<List<ConsignListVO>> getConsignList(){
		//查询已授权表记录
		LambdaQueryWrapper<PlatformAuthorization> query = Wrappers.lambdaQuery(PlatformAuthorization.class);
		query.eq(PlatformAuthorization::getState, 1);
		List<PlatformAuthorization> platformAuthorizations = paMapper.selectList(query);
		Map<Long, List<PlatformAuthorization>> collect = platformAuthorizations.stream().collect(Collectors.groupingBy(PlatformAuthorization::getConsignConfigId));
		LambdaQueryWrapper<Consign> consignLambdaQueryWrapper = Wrappers.lambdaQuery(Consign.class);
		consignLambdaQueryWrapper.eq(Consign::getNowStock, 0).eq(Consign::getConsignState, 2);
		List<Consign> list = consignService.list(consignLambdaQueryWrapper);
		ConsignListVO consignListVO = null;
		List<ConsignListVO> consignListVOS = new ArrayList<>();
		Map<Long, List<Consign>> collect1 = list.stream().collect(Collectors.groupingBy(Consign::getConsignConfigId));
		for (Map.Entry<Long, List<Consign>> entry : collect1.entrySet()) {
			//取出之前授权的列表
			List<PlatformAuthorization> platformAuthorizations1 = collect.get(entry.getKey());
			consignListVO = new ConsignListVO();
			Integer num = entry.getValue().size();
			if(ObjectUtil.isNotNull(platformAuthorizations1)){
				for (PlatformAuthorization platformAuthorization : platformAuthorizations1) {
					//判断授权数量是否大于待付款数量
					if(num > platformAuthorization.getTotalNum()){
						num = num - platformAuthorization.getTotalNum();
					}else{
						num = 0;
					}
				}
			}
			if(num > 0){
				consignListVO.setConsignConfigId(entry.getKey());
				consignListVO.setOrderNum(num);
				consignListVO.setOrderPrice(new BigDecimal(entry.getValue().get(0).getConsignPrice()).setScale(2, BigDecimal.ROUND_DOWN));
				consignListVOS.add(consignListVO);
			}
		}
		return R.data(consignListVOS);
	}

	@GetMapping("/finance/order-page")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "我的订单", notes = "传入用户ID，支付状态 0:全部，1待付款，2:待发货，3待收货，4已完成，5已取消")
	public R<List<OrderVO>> orderPage(@ApiParam(value = "用户ID", required = true) @RequestParam Long userId,
									  @ApiParam(value = "支付状态", required = false) @RequestParam(required = false) Integer payFlag,
									  Query query) {
		Order order = new Order();
		order.setUserId(userId);
		order.setOrderType(1);//普通订单
		if(!StringUtil.isEmpty(payFlag)){
			if(payFlag != 0){
				order.setPayFlag(payFlag); //订单状态
			}
		}
		IPage<Order> pages = orderService.page(Condition.getPage(query),
			Condition.getQueryWrapper(order).orderByDesc("create_time"));
		return R.data(OrderWrapper.build().listVO(pages.getRecords()));
	}

	@GetMapping("/finance/consign-selfPage")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "我的仓单", notes = "传入用户ID，状态: 1寄售中，2:待收款，3:已收款, 不传或者传其他则查询全部")
	public R<List<ConsignVO>> consignPage(@ApiParam(value = "用户ID", required = true) @RequestParam(required = true) Long userId,
										  @ApiParam(value = "状态", required = false) @RequestParam(required = false) Integer status,
										  Query query) {
		Consign consign = new Consign();
		consign.setConsignUserId(userId);
		if(status == 1){
			consign.setConsignState(1); //寄售中
		}else if(status == 2){
			consign.setConsignState(2); //待收款
		}else if(status == 3){
			consign.setConsignState(3); //已收款
		}//查询全部
		IPage<Consign> pages = consignService.page(Condition.getPage(query),
			Condition.getQueryWrapper(consign).orderByDesc("create_time"));
		return R.data(ConsignWrapper.build().listVO(pages.getRecords()));
	}

	@PostMapping("/finance/consign-selfTake")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "仓单提货", notes = "我的仓单提货")
	public R consignTake(@Valid @RequestBody OrderTakeRequest request) {
		return R.data(orderService.consignSelfTake(request));
	}

	@PostMapping("/finance/order-cancel")
	@ApiOperationSupport(order = 6)
	@ApiOperation(value = "取消订单", notes = "传入订单号")
	public R orderCancel(@ApiParam(value = "订单ID", required = true) @RequestParam Long id) {
		Order order = new Order();
		order.setId(id);
		order.setPayFlag(5); //已取消
		return R.status(orderService.updateById(order));
	}

	@PostMapping("/finance/order-confirm")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "确认收货", notes = "待收货变为已完成")
	public R orderConfirm(@ApiParam(value = "订单ID", required = true) @RequestParam Long orderId,
						  @ApiParam(value = "用户id", required = true) @RequestParam(required = false) Long userId) {
		return R.status(orderService.orderEnd(orderId,userId));
	}

	/**
	 * 预支付统一收单
	 * @param outTradeNo 订单号
	 * @param orderNo 授权
	 * @param price 打款金额
	 * @return R
	 */
	public boolean orderConsign(String outTradeNo, String orderNo, Double price) {
		//查询抢购订单数据
		Order order = orderService.getOne(Wrappers.<Order>lambdaQuery().eq(Order::getOutTradeNo, outTradeNo));

		if (ObjectUtil.isNull(order)){
			return false;
		}
		//通过授权号查询用户授权信息
		OrderGrant orderGrant = orderGrantService.getOne(Wrappers.<OrderGrant>lambdaQuery().eq(OrderGrant::getOrderNo, orderNo));
		if (ObjectUtil.isNull(orderGrant)) {
			return false;
		}
		//获取剩余预售授权数量
		Integer nowNum = orderGrant.getNowNum();
		UserApp userApp = new UserApp();
		UserApp query = userApp.selectOne(Wrappers.<UserApp>lambdaQuery().eq(UserApp::getUserId, orderGrant.getUserId()));
		JSONObject data = new JSONObject();
		data.put("out_trade_no", outTradeNo);
		data.put("total_amount", price);
		data.put("subject", "中宏酒业");
		data.put("product_code", "PRE_AUTH_ONLINE");
		data.put("auth_no", orderGrant.getAuthNo());
		data.put("body", orderGrant.getAuthNo());
		if (nowNum == 1){//判断剩余授权数量是否为1
			//授权数量为1是进行解冻
			data.put("auth_confirm_mode", "COMPLETE"); //解冻
		}else{
			//授权数量不为1时，交易继续，只进行收单操作
			data.put("auth_confirm_mode", "NOT_COMPLETE");//不解冻
		}
		data.put("seller_id", properties.getPayeeUserId()); //收款方
//		data.put("seller_id", properties.getPayeeUserId()); //收款方
		data.put("buyer_id", query.getAlipayUserId()); //买家ID //2088012801069195
		//APP支付
		AlipayTradePayRequest request = new AlipayTradePayRequest();
		request.setNotifyUrl(properties.getDomain() + TRADE_URL); //异步通知地址
		request.setBizContent(data.toJSONString()); //业务参数
		//APP支付
		try {
			//订单绑定授权号
			Order update = new Order();
			update.setId(order.getId());
			update.setGrantNo(orderGrant.getAuthNo());
			boolean flg = orderService.updateById(update);
			if (!flg){
				log.info("订单绑定失败 + update.toString()");
			}
			//普通模式 使用 execute
			//证书使用 使用 certificateExecute
			AlipayTradePayResponse response = client.certificateExecute(request);
			if (response.isSuccess()){
				orderService.payConsignSuccess(order);
				return true;
			}else{
				orderGrantService.remove(Wrappers.<OrderGrant>lambdaQuery()
					.eq(OrderGrant::getId,orderGrant.getId())
					.eq(OrderGrant::getStatus, 0));
				log.info("订单绑定失败 + 删除预授权数据");
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return false;
	}

}
