package com.neusoft.smart.pos.member.service;

import com.neusoft.smart.pos.constants.DictionaryConstant;
import com.neusoft.smart.pos.dto.member.request.*;
import com.neusoft.smart.pos.dto.member.response.DetailedMemberResponse;
import com.neusoft.smart.pos.dto.member.response.MemberCapitalChangeResponse;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.BeanUtil;
import com.neusoft.smart.pos.member.constants.MemberCapitalChangeType;
import com.neusoft.smart.pos.member.constants.MemberErrorCode;
import com.neusoft.smart.pos.member.persistent.domain.MemberCapitalChange;
import com.neusoft.smart.pos.member.persistent.domain.MemberCapitalChangeExt;
import com.neusoft.smart.pos.member.persistent.domain.MemberCard;
import com.neusoft.smart.pos.member.persistent.domain.MemberCardExample;
import com.neusoft.smart.pos.member.persistent.ext.domain.MemberCapitalChangeQuery;
import com.neusoft.smart.pos.member.persistent.repository.MemberCapitalChangeRepository;
import com.neusoft.smart.pos.member.persistent.repository.MemberCardRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
public class MemberCapitalChangeService implements MemberCapitalChangeServiceInterface {
	
	@Autowired
	private MemberCapitalChangeRepository memberCapitalChangeRepository;
	
	@Autowired
	private MemberCardRepository memberCardRepository;
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private MemberBusinessService memberBusinessService;
	
	@Override
	@Transactional
	public BigDecimal recharge(MemberRechargeRequest memberRechargeRequest) {
		//存在数据说明已经充值过
		if (this.getChangeByOrderId(memberRechargeRequest.getRechargeOrderNo(), MemberCapitalChangeType.RECHARGE.getCode()) > 0) {
			throw new BusinessCommonException(MemberErrorCode.RECHARGE_NUM_DUPLICATE);
		}
		MemberCard memberCard = this.getCard(memberRechargeRequest.getCardNum());
		BigDecimal balance = memberCard.getCardBalance();
		memberCard.setCardBalance(memberCard.getCardBalance().add(memberRechargeRequest.getRechargeAmount()));
		memberCard.setLastRechargeAmount(memberRechargeRequest.getRechargeAmount());
		memberCard.setUpdatedTime(new Date());
		//更新卡数据
		this.updateCard(memberCard);
		//存变更数据
		BigDecimal afterBalance = memberCard.getCardBalance();
		MemberCapitalChange memberCapitalChange = new MemberCapitalChange();
		memberCapitalChange.setMemberCardId(memberCard.getCardId());
		memberCapitalChange.setChangeOrderId(memberRechargeRequest.getRechargeOrderNo());
		memberCapitalChange.setAmountChange(memberRechargeRequest.getRechargeAmount());//正数 意味着加钱
		memberCapitalChange.setAmountBefore(balance);
		memberCapitalChange.setAmountAfter(afterBalance);
		memberCapitalChange.setContent("会员充值");
		memberCapitalChange.setChangeType(MemberCapitalChangeType.RECHARGE.getCode());
		memberCapitalChange.setChangeTime(memberRechargeRequest.getRechargeTime());
		this.changeLog(memberCapitalChange);
		return memberCard.getCardBalance();
	}
	
	@Override
	@Transactional
	public DetailedMemberResponse trade(MemberTransactionRequest memberTransactionRequest) {
		//存在数据说明已经交易过
		if (this.getChangeByOrderId(memberTransactionRequest.getTransactionOrderNo(), MemberCapitalChangeType.TRANSACTION.getCode()) > 0) {
			throw new BusinessCommonException(MemberErrorCode.ORDER_NUM_DUPLICATE);
		}
		MemberCard memberCard = this.getCard(memberTransactionRequest.getCardNum());
		
		MemberCapitalChange memberCapitalChange = new MemberCapitalChange();
		memberCapitalChange.setMemberCardId(memberCard.getCardId());
		memberCapitalChange.setChangeOrderId(memberTransactionRequest.getTransactionOrderNo());
		//会员卡支付
		if (DictionaryConstant.PAY_TYPE_HYK.getCode().equals(memberTransactionRequest.getTransactionMode().toString())
				|| DictionaryConstant.PAY_TYPE_FKSY.getCode().equals(memberTransactionRequest.getTransactionMode().toString())) {
			//此处不要密码校验
			if (DictionaryConstant.PAY_TYPE_HYK.getCode().equals(memberTransactionRequest.getTransactionMode().toString()) &&
					memberCard.isNeedPwd() &&
					!passwordEncoder.matches(memberTransactionRequest.getCardPassword(), memberCard.getCardPassword())) {
				throw new BusinessCommonException(MemberErrorCode.WRONG_MEMBER_CARD_PASSWORD);
			}
			
			BigDecimal balance = memberCard.getCardBalance();
			memberCard.setCardBalance(memberCard.getCardBalance().subtract(memberTransactionRequest.getTransactionAmount()));
			memberCard.setUpdatedTime(new Date());
			BigDecimal afterBalance = memberCard.getCardBalance();
			if (!memberTransactionRequest.getCanBeNegative() && afterBalance.compareTo(new BigDecimal("0.00")) < 0) {
				throw new BusinessCommonException(MemberErrorCode.MEMBER_CARD_INSUFFICIENT_BALANCE);
			}
			memberCapitalChange.setAmountChange(memberTransactionRequest.getTransactionAmount().negate());//取反 意味着扣钱
			memberCapitalChange.setAmountBefore(balance);
			memberCapitalChange.setAmountAfter(afterBalance);
			memberCapitalChange.setContent("会员卡支付消费");
		} else {
			memberCapitalChange.setContent("会员消费");
		}
		Integer point = memberCard.getCardPoint();
		memberCapitalChange.setChangeType(MemberCapitalChangeType.TRANSACTION.getCode());
		memberCapitalChange.setChangeTime(memberTransactionRequest.getTransactionTime());
		memberCapitalChange.setPointBefore(point);
		memberCapitalChange.setPointChange(memberTransactionRequest.getTransactionAmount().intValue());
		Integer afterPoint = memberCard.getCardPoint() + memberTransactionRequest.getTransactionAmount().intValue();
		memberCapitalChange.setPointAfter(afterPoint);
		//存下变更表
		this.changeLog(memberCapitalChange);
		
		//不管是啥都处理一下积分,这个暂时按照一元一积分处理 TODO
		memberCard.setCardPoint(afterPoint);
		//更新卡数据
		this.updateCard(memberCard);
		DetailedMemberResponse detailedMemberResponse = new DetailedMemberResponse();
		detailedMemberResponse.setBalance(memberCard.getCardBalance());
		detailedMemberResponse.setPoint(memberCapitalChange.getPointChange());
		detailedMemberResponse.setCreatedTime(new Date());
		return detailedMemberResponse;
	}
	
	@Override
	public void refund(MemberRefundRequest memberRefundRequest) {
		//存在数据说明已经交易过
		if (this.getChangeByOrderId(memberRefundRequest.getRefundOrderNo(), MemberCapitalChangeType.REFUND.getCode()) > 0) {
			throw new BusinessCommonException(MemberErrorCode.REFUND_NUM_DUPLICATE1);
		}
		MemberCard memberCard = this.getCard(memberRefundRequest.getCardNum());
		MemberCapitalChange memberCapitalChange = new MemberCapitalChange();
		memberCapitalChange.setMemberCardId(memberCard.getCardId());
		memberCapitalChange.setChangeOrderId(memberRefundRequest.getRefundOrderNo());
		//会员卡支付
		if (DictionaryConstant.PAY_TYPE_HYK.getCode().equals(memberRefundRequest.getTransactionMode().toString())) {
			BigDecimal balance = memberCard.getCardBalance();
			memberCard.setCardBalance(memberCard.getCardBalance().add(memberRefundRequest.getRefundAmount()));
			BigDecimal afterBalance = memberCard.getCardBalance();

			memberCapitalChange.setAmountChange(memberRefundRequest.getRefundAmount());//退款 加钱 正数
			memberCapitalChange.setAmountBefore(balance);
			memberCapitalChange.setAmountAfter(afterBalance);
		}

		Integer point = memberCard.getCardPoint();
		memberCapitalChange.setPointBefore(point);
		memberCapitalChange.setChangeTime(memberRefundRequest.getRefundTime());
		memberCapitalChange.setPointChange(memberRefundRequest.getRefundAmount().negate().intValue());
		Integer afterPoint = memberCard.getCardPoint() - memberRefundRequest.getRefundAmount().intValue();
		memberCapitalChange.setPointAfter(afterPoint);

		memberCapitalChange.setContent("会员退款");
		memberCapitalChange.setChangeType(MemberCapitalChangeType.REFUND.getCode());
		//存下变更表
		this.changeLog(memberCapitalChange);

		memberCard.setCardPoint(afterPoint > 0 ? afterPoint : 0);
		//更新卡数据
		this.updateCard(memberCard);
	}
	
	@Override
	public void pointWriteOff(MemberPointWriteOffRequest memberPointWriteOffRequest) {
		MemberCard memberCard = this.getCard(memberPointWriteOffRequest.getCardNum());
		if (memberCard.getCardPoint().compareTo(memberPointWriteOffRequest.getWriteOffPoint()) < 0) {
			throw new BusinessCommonException(MemberErrorCode.MEMBER_CARD_POINT_SHORTAGE);
		}
		MemberCapitalChange memberCapitalChange = new MemberCapitalChange();
		memberCapitalChange.setMemberCardId(memberCard.getCardId());
		memberCapitalChange.setChangeOrderId(System.currentTimeMillis() + "");
		
		Integer point = memberCard.getCardPoint();
		memberCapitalChange.setChangeType(MemberCapitalChangeType.WRITE_OFF.getCode());
		memberCapitalChange.setChangeTime(new Date());
		memberCapitalChange.setPointBefore(point);
		Integer afterPoint = point - memberPointWriteOffRequest.getWriteOffPoint();
		memberCapitalChange.setPointChange(memberPointWriteOffRequest.getWriteOffPoint() * (-1));
		memberCapitalChange.setPointAfter(afterPoint);
		memberCapitalChange.setContent("积分核销");
		//存下变更表
		this.changeLog(memberCapitalChange);
		
		memberCard.setCardPoint(afterPoint);
		//更新卡数据
		this.updateCard(memberCard);
	}
	
	@Override
	@Transactional
	public void changeBalance(Integer cardId, BigDecimal newBalance) {
		MemberCard memberCard = memberCardRepository.get(cardId);
		BigDecimal beforeBalance = memberCard.getCardBalance();
		memberCard.setCardBalance(newBalance);
		//更新卡数据
		this.updateCard(memberCard);
		//存下变更表
		MemberCapitalChange memberCapitalChange = new MemberCapitalChange();
		memberCapitalChange.setMemberCardId(memberCard.getCardId());
		memberCapitalChange.setChangeOrderId(UUID.randomUUID().toString());//随个uuid占位
		memberCapitalChange.setAmountChange(newBalance.subtract(beforeBalance));//修改后减去修改前,就是差额,负的就是扣减
		memberCapitalChange.setAmountBefore(beforeBalance);
		memberCapitalChange.setAmountAfter(newBalance);
		memberCapitalChange.setContent("手动调整余额");
		memberCapitalChange.setChangeType(MemberCapitalChangeType.MODIFY.getCode());
		this.changeLog(memberCapitalChange);
	}
	
	@Override
	public Integer getChangeByOrderId(String orderId, Integer changeType) {
		MemberCapitalChangeQuery memberCapitalChangeQuery = new MemberCapitalChangeQuery();
		memberCapitalChangeQuery.setChangeOrderId(orderId);
		memberCapitalChangeQuery.setChangeType(changeType);
		return memberCapitalChangeRepository.queryChangeCount(memberCapitalChangeQuery);
	}
	
	
	@Override
	@Transactional
	public void changeLog(MemberCapitalChange memberCapitalChange) {
		memberCapitalChangeRepository.createChange(memberCapitalChange);
	}
	
	@Override
	public List<MemberCapitalChangeResponse> getList(MemberCapitalChangeQueryRequest memberCapitalChangeQueryRequest) {
		List<MemberCapitalChangeExt> poList;
		switch (memberBusinessService.getBusiness()) {
			case 1://普通会员卡
				poList = memberCapitalChangeRepository.getList(BeanUtil.parse(memberCapitalChangeQueryRequest, MemberCapitalChangeQuery.class));
				break;
			case 2://食堂会员卡
				poList = memberCapitalChangeRepository.getList4Canteen(BeanUtil.parse(memberCapitalChangeQueryRequest, MemberCapitalChangeQuery.class));
				break;
			default:
				poList = memberCapitalChangeRepository.getList(BeanUtil.parse(memberCapitalChangeQueryRequest, MemberCapitalChangeQuery.class));
				break;
		}
		return BeanUtil.parseList(poList, MemberCapitalChangeResponse.class);
		
	}
	
	@Override
	public Integer getCount(MemberCapitalChangeQueryRequest memberCapitalChangeQueryRequest) {
		switch (memberBusinessService.getBusiness()) {
			case 1://普通会员卡
				return memberCapitalChangeRepository.getCount(BeanUtil.parse(memberCapitalChangeQueryRequest, MemberCapitalChangeQuery.class));
			case 2://食堂会员卡
				return memberCapitalChangeRepository.getCount4Canteen(BeanUtil.parse(memberCapitalChangeQueryRequest, MemberCapitalChangeQuery.class));
			default:
				return memberCapitalChangeRepository.getCount(BeanUtil.parse(memberCapitalChangeQueryRequest, MemberCapitalChangeQuery.class));
		}
		
	}
	
	
	private MemberCard getCard(String cardNum) {
        MemberCard memberCard = memberCardRepository.getActiveCardByCardNum(cardNum);
		if (null == memberCard) {
			throw new BusinessCommonException(MemberErrorCode.MEMBER_CARD_NOT_EXIST);
		} else if (!memberCard.getIsActive().equals(1)) {
			throw new BusinessCommonException(MemberErrorCode.MEMBER_CARD_CAN_NOT_USE);
		}
		return memberCard;
	}
	
	private void updateCard(MemberCard memberCard) {
		MemberCardExample memberCardExample = new MemberCardExample();
		memberCardExample.createCriteria().andVersionEqualTo(memberCard.getVersion())
				.andCardIdEqualTo(memberCard.getCardId());
		Integer updateResult = memberCardRepository.update(memberCard, memberCardExample);
		if (updateResult == 0) {
			throw new BusinessCommonException(MemberErrorCode.MEMBER_CARD_BALANCE_CHANGE_ERROR);
		}
	}
}
