package com.community.huiju.service.impl;

import com.community.commom.constant.Constant;
import com.community.commom.mode.ResponseBean;
import com.community.commom.session.UserElement;
import com.community.huiju.common.perproties.PayNotifyPerproties;
import com.community.huiju.common.wxpay.HfWxConfig;
import com.community.huiju.common.wxpay.WXPay;
import com.community.huiju.common.wxpay.WXPayConstants;
import com.community.huiju.common.wxpay.WXPayUtil;
import com.community.huiju.dao.*;
import com.community.huiju.exception.WisdomException;
import com.community.huiju.model.*;
import com.community.huiju.service.IFuShiService;
import com.community.huiju.service.ITaUserLicenseService;
import com.community.huiju.service.WxPayServiceI;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author FXF
 * @date 2018-10-25
 */
@Service("wxPayService")
@Transactional(rollbackFor = Exception.class)
public class WxPayServiceImpl implements WxPayServiceI {
	private Logger log = LoggerFactory.getLogger(WxPayServiceImpl.class);
	
	@Autowired
	private TpBillInvoiceMapper tpBillInvoiceMapper;
	
	@Autowired
	private TpBillStatementMapper tpBillStatementMapper;

	@Autowired
	private TpBillMapper tpBillMapper;

	@Autowired
	private TaUserMapper taUserMapper;

	@Autowired
	private TaSysRoleMapper taSysRoleMapper;

	@Autowired
	private TpMessageMapper tpMessageMapper;

	@Autowired
	private TpBillOrderMapper tpBillOrderMapper;

	@Autowired
	private TaUserVerifyMapper taUserVerifyMapper;

	@Autowired
	private TpBuildingOwnerInfoMapper tpBuildingOwnerInfoMapper;

	@Autowired
	private PayNotifyPerproties payNotifyPerproties;

	@Autowired
	private TaUserLicenseOrderMapper taUserLicenseOrderMapper;

	@Autowired
	private IFuShiService iFuShiService;

	@Autowired
	private TaUserLicenseMapper taUserLicenseMapper;

	@Autowired
	private ITaUserLicenseService iTaUserLicenseService;


	/**
	 * 微信支付统一下单
	 *
	 * @return
	 * @param orderNo
	 * @param userElement
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, String> wxUnifiedOrder(String orderNo, String type, UserElement userElement) throws Exception {
		HfWxConfig config = new HfWxConfig();
		WXPay wxpay = new WXPay(config);

		Map<String, Object> orderPriceAndNotifyUrl = getOrderPriceAndNotifyUrl(type, orderNo, "wx");

		String typeName = Constant.PAY_TYPE_BILL.equals(type) ? "物业缴费" : Constant.PAY_TYPE_CAR.equals(type) ? "车缴费" : "缴费";

		//下单
		Map<String, String> data = new HashMap<String, String>();
		data.put("body", typeName);
		//商品号唯一
		data.put("out_trade_no", orderNo);
		data.put("device_info", "");
		data.put("fee_type", "CNY");
		//金额 后台计算
		data.put("total_fee", String.valueOf(orderPriceAndNotifyUrl.get("payPrice")));
		//终端IP
		data.put("spbill_create_ip", "123.12.12.123");
		//回调地址
		data.put("notify_url", String.valueOf(orderPriceAndNotifyUrl.get("notifyUrl")));
		// 此处指定为APP支付
		data.put("trade_type", "APP");
		Map<String, String> resp = wxpay.unifiedOrder(data);
		log.info("下单成功：{}", resp);
		if (resp.get("result_code").equalsIgnoreCase(WXPayConstants.FAIL)){
			throw new Exception(resp.get("err_code_des"));
		}
		//插入下单记录表
		
		//第二次重新生成签名
		Map<String, String> secondSignData = new HashMap<String, String>();
		long timestamp = Instant.now().getEpochSecond();
		secondSignData.put("appid", config.getAppID());
		secondSignData.put("partnerid", config.getMchID());
		secondSignData.put("prepayid", resp.get("prepay_id"));
		secondSignData.put("noncestr", resp.get("nonce_str"));
		secondSignData.put("timestamp", String.valueOf(timestamp));
		secondSignData.put("package", "Sign=WXPay");
		secondSignData.put("sign", WXPayUtil.generateSignature(secondSignData, config.getKey(), WXPayConstants.SignType.MD5));

		log.info("订单: {}，订单类型: {}, 状态变更为正在支付", orderNo, type);

		// 更改订单状态 为正在支付
		updateOrderStatus(orderNo, type, "2");
		return secondSignData;
	}

	/**
	 * 根据订单类型获取 金额 和 回调地址
	 * @param type
	 * @param orderNo
	 * @param notifyType wx 微信, ali 支付宝
	 * @return
	 * @throws Exception
	 */
	@Override
	public Map<String,Object> getOrderPriceAndNotifyUrl(String type, String orderNo, String notifyType) throws Exception {
		Map<String,Object> orderMap = Maps.newHashMap();

		// 物业缴费
		if (Constant.PAY_TYPE_BILL.equals(type)) {
			//获取支付金额
			List<TpBillOrder> billOrderList = tpBillOrderMapper.selectByOrderBumber(orderNo);
			if (CollectionUtils.isEmpty(billOrderList)){
				throw new Exception("订单不存在");
			}
			// 检测订单是否 已关闭
			billOrderList.forEach(e-> {
				if ("3".equals(e.getOrderStatus())) {
					throw new WisdomException("无法支付已关闭的订单!");
				}
			});
			// 计算金额
			Long payPrice = billOrderList.stream().mapToLong(e -> tpBillInvoiceMapper.selectByPrimaryKey(e.getTpBillInvoiceId()).getPayPrice()).sum();
			orderMap.put("orderNo", orderNo);
			orderMap.put("payPrice", String.valueOf(payPrice));
			orderMap.put("notifyUrl", "wx".equals(notifyType) ? payNotifyPerproties.getWxBillNotify() : payNotifyPerproties.getAliBillNotify());

		} else if (Constant.PAY_TYPE_CAR.equals(type)) { // 车缴费
			List<TaUserLicenseOrder> userLicenseOrders = taUserLicenseOrderMapper.selectByOrderNumber(orderNo);
			if (CollectionUtils.isEmpty(userLicenseOrders)) {
				throw new Exception("订单不存在");
			}
			// 检测订单是否 已关闭
			userLicenseOrders.forEach(e-> {
				if ("3".equals(e.getOrderStatus())) {
					throw new WisdomException("无法支付已关闭的订单!");
				}
			});

			// 总额
			Long payPrice = userLicenseOrders.stream().map(e -> Long.parseLong(e.getExtensionPrice())).count();
			orderMap.put("orderNo", orderNo);
			orderMap.put("payPrice", String.valueOf(payPrice));
			orderMap.put("notifyUrl", "wx".equals(notifyType) ? payNotifyPerproties.getWxCarNotify() : payNotifyPerproties.getAliCarNotify());
		}

		return orderMap;
	}




	/**
	 * 支付成功的回调
	 *
	 * @return
	 * @param resultMap
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public String wxBillNotify(Map<String, String> resultMap) throws Exception {
		String outTradeNo = resultMap.get("out_trade_no");
		List<TpBillOrder> billOrderList = tpBillOrderMapper.selectByOrderBumber(outTradeNo);
		if (CollectionUtils.isEmpty(billOrderList)){
			return "不存在的订单";
		}

		// 缴费人在准备支付状态下更新, 这里是微信的回调所有没有 token

		for ( TpBillOrder billOrder : billOrderList){
			TpBillInvoice tpBillInvoice = tpBillInvoiceMapper.selectByPrimaryKey(billOrder.getTpBillInvoiceId());

			// 更新为正在支付状态
			// 更改收费单的 缴费时间, 修改人, 修改时间
			tpBillInvoice.setBillStatus("1");
			tpBillInvoice.setPayDate(new Date());
			tpBillInvoice.setUpdateDate(new Date());
			// 缴费方式  0：微信支付  1：线下缴费 2.支付宝支付
			tpBillInvoice.setPayType(resultMap.get("pay_type"));
			tpBillInvoiceMapper.updateByPrimaryKeySelective(tpBillInvoice);

			//插入流水账单表
			TpBillStatement tpBillStatement = new TpBillStatement();
			tpBillStatement.setBillInvoiceId(tpBillInvoice.getId());
			tpBillStatement.setCommunityId(tpBillInvoice.getCommunityId());
			tpBillStatement.setTaUserId(tpBillInvoice.getTaUserId());
			tpBillStatement.setPayPrice(tpBillInvoice.getPayPrice());
			tpBillStatement.setPayName(tpBillInvoice.getPayName());
			tpBillStatement.setPayRemark(tpBillInvoice.getBillName());
			tpBillStatement.setPayType(resultMap.get("pay_type"));
			tpBillStatement.setCreateTime(new Date());
			tpBillStatementMapper.insert(tpBillStatement);

			// 更新 收费单流水id
			tpBillInvoice.setBillStatementId(tpBillStatement.getId());
			tpBillInvoiceMapper.updateByPrimaryKeySelective(tpBillInvoice);

			// 更新收费组的 未交费用户数 和 已缴费用户数
			TpBill tpBill = tpBillMapper.selectByPrimaryKey(tpBillInvoice.getBillId());
			tpBill.setPayedNum(tpBill.getPayedNum() + 1);
			tpBill.setUnpayedNum(tpBill.getUnpayedNum() - 1);
			// 如果为零, 表示这个收费组收费完成
			if (tpBill.getUnpayedNum() <= 0) {
				tpBill.setBillStatus("1");
				tpBill.setUnpayedNum(0);
			}
			tpBillMapper.updateByPrimaryKeySelective(tpBill);

			// 把相对应的APP端, 代办消息设置为无效
//			Map<String, Object> map = Maps.newHashMap();
//			map.put("communityId", tpBillInvoice.getCommunityId());
//			map.put("billInvoiceId", tpBillInvoice.getId());
//			map.put("userId", tpBillInvoice.getTaUserId());
//			TpMessage tpMessage = tpMessageMapper.selectBillinvoiceMessage(map);
//			tpMessage.setStatus("0");
//			tpMessageMapper.updateByPrimaryKeySelective(tpMessage);
		}

		log.info("订单: {}，订单类型: {}, 状态变更为支付成功", outTradeNo, Constant.PAY_TYPE_BILL);

		// 更改订单状态 为支付成功
		updateOrderStatus(outTradeNo, Constant.PAY_TYPE_BILL, "1");

		return "success";
	}
	
	/**
	 * 订单查询
	 *
	 * @return
	 */
	@Override
	public Map<String, String> wxOrderQuery(String outTradeNo) throws Exception {
		HfWxConfig config = new HfWxConfig();
		WXPay wxpay = new WXPay(config);
		
		Map<String, String> data = new HashMap<String, String>();
		data.put("out_trade_no", outTradeNo);
		return wxpay.orderQuery(data);
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public String wxStartPay(List<Integer> idArray, String type, Integer extensionMonth, UserElement userElement) throws Exception {
		if (StringUtils.isBlank(type)) {
			throw new WisdomException("type 不能为空！");
		}

		// 缴费的用户
		TaUser taUser = taUserMapper.selectByPrimaryKey(userElement.getId());

		Random random = new Random();
		String orderNo = String.valueOf(System.currentTimeMillis()) + random.nextInt();

		// 创建订单
		createOrder(idArray, type, taUser, userElement, orderNo, extensionMonth, null);

		return orderNo;
	}

	/**
	 * 创建订单
	 * @param idArray
	 * @param type
	 * @param taUser
	 * @param userElement
	 * @param orderNo
	 * @param extensionMonth 延期月份，也就是延期几个月！
	 *                       	只有在 车缴费的时候才有效
	 * @param paymentType 缴费方式 1是支付宝 2是微信支付
	 * @throws Exception
	 */
	private void createOrder(List<Integer> idArray, String type, TaUser taUser, UserElement userElement, String orderNo, Integer extensionMonth, String paymentType) throws Exception {
		// 物业缴费
		if (Constant.PAY_TYPE_BILL.equals(type)) {
			//获取支付金额
			for (Integer billInvoiceId : idArray) {
				TpBillInvoice tpBillInvoice = tpBillInvoiceMapper.selectByPrimaryKey(billInvoiceId);
				if (null == tpBillInvoice){
					throw new Exception("订单不存在");
				}else if (!tpBillInvoice.getBillStatus().equals("0")){
					throw new Exception("正在支付的订单");
				}

				TpBillOrder tpBillOrder = new TpBillOrder();
				tpBillOrder.setCommunityId(userElement.getCommunityId());
				tpBillOrder.setTpBillId(tpBillInvoice.getBillId());
				tpBillOrder.setTpBillInvoiceId(tpBillInvoice.getId());
				tpBillOrder.setCreateDate(new Date());
				tpBillOrder.setCreateUser(userElement.getId());
				tpBillOrder.setUpdateDate(new Date());
				tpBillOrder.setUpdateUser(userElement.getId());
				tpBillOrder.setOrderBumber(orderNo);
				tpBillOrder.setPayPhone(taUser.getLoginName());
				tpBillOrder.setOrderStatus("0");

				tpBillOrderMapper.insertSelective(tpBillOrder);

			}
			// 修改缴费人, 修改为正在缴费
			updateBillInvoiceBillStatus(idArray, taUser.getUserName(), "3");

			// 车缴费
		} else if (Constant.PAY_TYPE_CAR.equals(type)) {
			if (null == extensionMonth || extensionMonth <= 0) {
				throw new Exception("延期月份不能为空，并且要大于0!");
			}

			for (Integer clicenseId : idArray) {
				// 根据车牌id，查询车牌
				TaUserLicense taUserLicense = taUserLicenseMapper.selectByPrimaryKey(clicenseId);
				// 获取车牌最新信息
				ResponseBean responseLicense = iTaUserLicenseService.getLicense(userElement, taUserLicense.getLicensePlate());
				Object licenseData = responseLicense.getData();
				if (null != licenseData && licenseData instanceof TaUserLicense) {
					taUserLicense = (TaUserLicense) licenseData;
				}

				// 校验车状态
				if (taUserLicense.getLicenseType().intValue() != 1) {
					throw new WisdomException("异常状态，不能缴月租费!");
				}

				// 校验是否，超出缴费有效期时间
				LocalDateTime expireDateLocalDateTime = LocalDateTime.ofInstant(taUserLicense.getExpireDate().toInstant(), ZoneId.systemDefault());
				expireDateLocalDateTime.plusDays(taUserLicense.getRenewTime());
				if (taUserLicense.getRenewTime().intValue() > 0 && System.currentTimeMillis() > expireDateLocalDateTime.toEpochSecond(ZoneOffset.of("+8"))) {
					throw new WisdomException("已超出续费时间，请找物业处理!");
				}

				TaUserLicenseOrder taUserLicenseOrder = new TaUserLicenseOrder();
				taUserLicenseOrder.setCommunityId(userElement.getCommunityId());
				taUserLicenseOrder.setTaUserId(userElement.getId());
				taUserLicenseOrder.setOrderNumber(orderNo);
				taUserLicenseOrder.setOrderStatus("0");
				taUserLicenseOrder.setCreateDate(new Date());
				taUserLicenseOrder.setCreateUser(userElement.getId());
				taUserLicenseOrder.setExtensionMonth(extensionMonth);

				// 费用
				String extensionPrice = BigDecimal.valueOf(Double.valueOf(taUserLicense.getUnitPrice()) / 100).multiply(BigDecimal.valueOf(extensionMonth)).toString();
				String price = String.valueOf(Double.valueOf(extensionPrice) * 100);
				taUserLicenseOrder.setExtensionPrice(price.substring(0, price.lastIndexOf(".")));

				taUserLicenseOrder.setPaymentTel(taUser.getLoginName());
				taUserLicenseOrder.setPaymentName(taUser.getUserName());
				taUserLicenseOrder.setPaymentType(paymentType);

				// 到期时间 (具体的到期时候，在支付回调里面以车辆管理系统为准)
				LocalDateTime localDateTime = LocalDateTime.ofInstant(taUserLicense.getExpireDate().toInstant(), ZoneId.systemDefault());
				localDateTime.plusMonths(extensionMonth);
				taUserLicenseOrder.setExpireDate(Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()));
				taUserLicenseOrder.setUnitPrice(taUserLicense.getUnitPrice());
				taUserLicenseOrder.setParkingLot(taUserLicense.getParkingLot());
				taUserLicenseOrder.setLicensePlate(taUserLicense.getLicensePlate());

				// 插入数据
				taUserLicenseOrderMapper.insertSelective(taUserLicenseOrder);

			}

		}
	}



	/**
	 * 取消支付
	 *
	 * @param outTradeNo
	 * @param userElement
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void wxCancelPay(String outTradeNo, String type, UserElement userElement) throws Exception {

		/**
		 * 如果是车缴费订单，就只直接更新 订单状态为关闭
		 */
		// 如果是车缴费
		if (Constant.PAY_TYPE_CAR.equals(type)) {
			// 更改订单状态 为订单已关闭
			updateOrderStatus(outTradeNo, type, "3");
			return;
		}

		// --------------------------- 物业缴费 --------------------------------

		//获取支付金额
		List<TpBillOrder> billOrderList = tpBillOrderMapper.selectByOrderBumber(outTradeNo);
		if (CollectionUtils.isEmpty(billOrderList)){
			throw new Exception("订单不存在");
		}

		List<TpBillInvoice> billInvoiceList = Lists.newArrayList();
		for (TpBillOrder tpBillOrder : billOrderList) {
			TpBillInvoice billInvoice = tpBillInvoiceMapper.selectByPrimaryKey(tpBillOrder.getTpBillInvoiceId());
			if (!billInvoice.getBillStatus().equals("2")){
				throw new Exception("不是正在支付的订单");
			}
			billInvoiceList.add(billInvoice);
		}

		// 缴费单id集合
		List<Integer> billInvoiceIdList = billInvoiceList.stream().map(e -> e.getId()).collect(Collectors.toList());

		//更新为 未支付状态
		updateBillInvoiceBillStatus(billInvoiceIdList, "","0");
		log.info("订单: {}， 订单类型: {}, 状态变更为取消支付", outTradeNo, type);

		// 更改订单状态 为订单已关闭
		updateOrderStatus(outTradeNo, type, "3");

	}

	@Override
	public String wxCarNotify(Map<String, String> resultMap) {

		String outTradeNo = resultMap.get("out_trade_no");
		String pay_type = resultMap.get("pay_type");
		String payTypeName = pay_type.equals("0") ? "微信支付" : pay_type.equals("2") ? "支付宝" : "未知";

		List<TaUserLicenseOrder> userLicenseOrderList = taUserLicenseOrderMapper.selectByOrderNumber(outTradeNo);
		if (CollectionUtils.isEmpty(userLicenseOrderList)){
			return "不存在的订单";
		}

		log.info("订单：{},订单类型: {} 开始推送到 车辆管理系统 ", outTradeNo, Constant.PAY_TYPE_CAR);

		TaUserLicenseOrder taUserLicenseOrder = userLicenseOrderList.get(0);
		TaUser taUser = taUserMapper.selectByPrimaryKey(taUserLicenseOrder.getTaUserId());

		// 推送到车辆管理系统
		iFuShiService.apiThirdPartyMonthCardPay(taUser.getLoginName(), "2",
				String.valueOf(taUserLicenseOrder.getExtensionMonth()),
				payTypeName, taUserLicenseOrder.getLicensePlate(),
				null, String.valueOf(Double.valueOf(taUserLicenseOrder.getExtensionPrice()) / 100));


		userLicenseOrderList.forEach(e-> {
			UserElement userElement = new UserElement();
			userElement.setCommunityId(e.getCommunityId());
			userElement.setId(e.getTaUserId());
			ResponseBean responseLicense = iTaUserLicenseService.getLicense(userElement, e.getLicensePlate());
			Object licenseData = responseLicense.getData();
			TaUserLicense taUserLicense = null;
			if (null != licenseData && licenseData instanceof TaUserLicense) {
				taUserLicense = (TaUserLicense) licenseData;
				e.setExpireDate(taUserLicense.getExpireDate());
			}
			e.setPaymentType(pay_type);
			e.setUpdateUser(e.getCreateUser());
			e.setUpdateDate(new Date());
			taUserLicenseOrderMapper.updateByPrimaryKeySelective(e);

		});


		log.info("订单: {}，订单类型: {}, 状态变更为支付成功", outTradeNo, Constant.PAY_TYPE_CAR);

		// 更改订单状态 为支付成功
		updateOrderStatus(outTradeNo, Constant.PAY_TYPE_CAR, "1");

		return "success";
	}

	/**
	 * 更新支付状态
	 * @param billInvoiceIdList
	 * @param status
	 */
	private void updateBillInvoiceBillStatus(List<Integer> billInvoiceIdList, String status) {
		billInvoiceIdList.forEach(e -> {
			TpBillInvoice tpBillInvoiceUpdate = new TpBillInvoice();
			tpBillInvoiceUpdate.setBillStatus(status);
			tpBillInvoiceUpdate.setId(e);
			tpBillInvoiceMapper.updateByPrimaryKeySelective(tpBillInvoiceUpdate);
		});

	}

	/**
	 * 更新支付状态
	 * @param billInvoiceIdList
	 * @param userName 缴费人
	 * @param status
	 */
	private void updateBillInvoiceBillStatus(List<Integer> billInvoiceIdList, String userName, String status) {
		billInvoiceIdList.forEach(e -> {
			TpBillInvoice tpBillInvoiceUpdate = new TpBillInvoice();
			tpBillInvoiceUpdate.setBillStatus(status);
			tpBillInvoiceUpdate.setId(e);
			tpBillInvoiceUpdate.setPayName(userName);
			tpBillInvoiceMapper.updateByPrimaryKeySelective(tpBillInvoiceUpdate);
		});
	}

	/**
	 * 更改订单状态
	 * @param orderNumber
	 * @param type
	 * @param status
	 */
	private void updateOrderStatus(String orderNumber, String type, String status){
		// 物业缴费
		if (Constant.PAY_TYPE_BILL.equals(type)) {
			List<TpBillOrder> billOrders = tpBillOrderMapper.selectByOrderBumber(orderNumber);
			billOrders.forEach(e-> {
				e.setOrderStatus(status);
				tpBillOrderMapper.updateByPrimaryKeySelective(e);
			});

			// 车缴费
		} else if (Constant.PAY_TYPE_CAR.equals(type)) {
			List<TaUserLicenseOrder> taUserLicenseOrders = taUserLicenseOrderMapper.selectByOrderNumber(orderNumber);
			taUserLicenseOrders.forEach(e-> {
				e.setOrderStatus(status);
				taUserLicenseOrderMapper.updateByPrimaryKeySelective(e);
			});
		}
	}
}
