package com.neusoft.smart.pos.card.controller;

import com.neusoft.smart.pos.card.constants.CardErrorCode;
import com.neusoft.smart.pos.card.constants.CardTradeConstants;
import com.neusoft.smart.pos.card.constants.CardType;
import com.neusoft.smart.pos.card.dto.GetCardInfoResponse;
import com.neusoft.smart.pos.card.dto.UpdateCardInfoRequest;
import com.neusoft.smart.pos.card.persistent.domain.Card;
import com.neusoft.smart.pos.card.persistent.domain.CardShopRelation;
import com.neusoft.smart.pos.card.persistent.repository.ICardRelationRepository;
import com.neusoft.smart.pos.card.service.CardService;
import com.neusoft.smart.pos.card.utils.SignUtils;
import com.neusoft.smart.pos.dto.card.request.ActivateCardRequest;
import com.neusoft.smart.pos.dto.card.request.DeactivateCardRequest;
import com.neusoft.smart.pos.dto.card.request.PosActivateCardRequest;
import com.neusoft.smart.pos.dto.card.response.GetBalanceResponse;
import com.neusoft.smart.pos.dto.member.request.MemberCardChangeRequest;
import com.neusoft.smart.pos.dto.member.request.UpdateCardPointRequest;
import com.neusoft.smart.pos.exchangeStrategy.constants.ExchangeStrategyConstants;
import com.neusoft.smart.pos.framework.dto.ResponseData;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.SpringUtils;
import com.neusoft.smart.pos.member.persistent.domain.Member;
import com.neusoft.smart.pos.member.service.MemberService;
import com.neusoft.smart.pos.redis.bean.DeviceInfo;
import com.neusoft.smart.pos.utils.PosDeviceRedisUtils;
import com.neusoft.smart.pos.utils.RequestHeaderUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Api(value = "卡接口", description = "卡接口")
@RestController
@Validated
public class CardController {
	@Resource
	private CardService cardService;

	@Resource
	private MemberService memberService;
	
	@Transactional
	@ApiOperation(value = "activate card")
    @PostMapping("/card/pos/activate")
    public ResponseData<?> addCard(@RequestBody PosActivateCardRequest posCreateCardRequest) {
        ActivateCardRequest createCardRequest = new ActivateCardRequest();
        BeanUtils.copyProperties(posCreateCardRequest, createCardRequest);
        fillOrgInfo(posCreateCardRequest.getSnCode(), createCardRequest);

		Card card = new Card();
		BeanUtils.copyProperties(createCardRequest, card);
		Integer cardId;

     	if(createCardRequest.getCardType() == CardType.MEMBER_CARD.getCode()) {
            /* 创建会员信息 */
     		Member member = new Member();
     		BeanUtils.copyProperties(createCardRequest, member);
     		memberService.createMember(member);
			Integer memberId = member.getMemberId();

    		/* 开卡*/
    		cardService.createCard(card);
			cardId = card.getCardId();
    		
    		/* 创建会员和卡对应关系*/
    		cardService.createRelation(memberId, cardId);
     	} else {
    		/* 开卡*/
    		cardService.createCard(card);
			cardId = card.getCardId();
     	}

		val cardRelationRepository = SpringUtils.getBean(createCardRequest.getBeanName(), ICardRelationRepository.class);

		/* 创建店铺和卡的对应关系 卡可用范围：集团下所有店铺*/
		cardRelationRepository.createCardShopRelation(cardId, createCardRequest.getOrg(), createCardRequest.getStore());
     	
     	/* 创建卡兑换策略(充值和积分两条, 1:1) 参数由前端传入，通过下载配置文件方式*/
		cardRelationRepository.createExchangeStrategy(cardId, 0, ExchangeStrategyConstants.EXCHANGE_STRATEGY_CATEGORY_RECHARGE.getCode(), createCardRequest.getRechargeStrategyParam());
		cardRelationRepository.createExchangeStrategy(cardId, 0, ExchangeStrategyConstants.EXCHANGE_STRATEGY_CATEGORY_POINT.getCode(), createCardRequest.getPointStrategyParam());

		/* 卡唯一性验证: 同一个组织中，cardNum和cardAnotherId两个参数唯一*/
		List<CardShopRelation> relations = cardRelationRepository.getCardShopRelation(cardId);
		cardService.verifyCardNumUniqueness(card, relations);
		cardService.verifyCardAnotherIdUniqueness(card, relations);
		return new ResponseData<>();
	}

	
	@Transactional
	@ApiOperation(value = "deactivate card")
	@PostMapping("/card/deactivate")
	public ResponseData<?> deactivateCard(@RequestBody DeactivateCardRequest deactivateCardRequest) {
		cardService.deactivateCard(deactivateCardRequest.getCardId());
		return new ResponseData<>();
	}

    private void fillOrgInfo(String SnCode, ActivateCardRequest createCardRequest) {

        if(StringUtils.isEmpty(SnCode)) {
            Integer orgId = RequestHeaderUtil.getOrgId();
            if(null == orgId) {
                throw new BusinessCommonException(CardErrorCode.NO_STORE_PROVIDED);
            }

            createCardRequest.setOrg(orgId);

            if(null != RequestHeaderUtil.getStoreIds() && RequestHeaderUtil.getStoreIds().size() > 0) {
                createCardRequest.setStore(RequestHeaderUtil.getStoreIds().get(0));
            }

        } else {
            DeviceInfo deviceInfo = PosDeviceRedisUtils.getDeviceInfoBySerialNo(SnCode);
            if (null == deviceInfo) {
                throw new BusinessCommonException(CardErrorCode.DEVICE_INFO_NOT_FOUND);
            }

            createCardRequest.setOrg(deviceInfo.getOrganizationId());
            createCardRequest.setStore(deviceInfo.getStoreId());
        }
    }

	@GetMapping("/memberCard/validate/{cardNum}")
	@ApiOperation(value = "卡号校验接口", notes = "卡号校验接口")
	public ResponseData<?> validateCardNum(@PathVariable String cardNum) {
		cardService.validateByCardNum(cardNum);
		return new ResponseData<>();
	}

	@Transactional
	@PutMapping("/memberCard/change")
	@ApiOperation(value = "会员卡更换接口", notes = "会员卡更换接口")
	public ResponseData<String> changeCard(@RequestBody MemberCardChangeRequest memberCardChangeRequest) {
		return new ResponseData<>(cardService.changeCard(memberCardChangeRequest));
	}

	@Transactional
	@PutMapping("/card/card-point")
	public ResponseData<Integer> updateCardPoint(@RequestBody UpdateCardPointRequest request) {
		cardService.updateCardPoint(request);
		return new ResponseData<>(1);
	}

	@Transactional
	@ApiOperation(value = "empty balance of card ")
	@PatchMapping("/card/emptyBalance")
	public ResponseData<?> emptyBalance(@RequestParam(value = "cardNum", defaultValue = "", required = false) String cardNum,
                                        @RequestParam(value = "cardAnotherId", required = false) String cardAnotherId,
                                        @RequestParam(value = "cardOtherId", defaultValue = "", required = false) String cardOtherId,
										@RequestParam(value = "sn") String sn) {
		cardService.emptyBalance(cardNum, cardAnotherId, cardOtherId, sn);
		return new ResponseData<>();
	}

	@GetMapping("/card/balance")
	@ApiOperation(value = "卡余额查询接口", notes = "卡余额查询接口")
	public ResponseData<Long> balance(
            @RequestParam(value = "cardNum", defaultValue = "", required = false) String cardNum,
            @RequestParam(value = "cardAnotherId", required = false) String cardAnotherId,
            @RequestParam(value = "cardOtherId", defaultValue = "", required = false) String cardOtherId) {
		return new ResponseData<>(cardService.getCardBalance(cardNum, cardAnotherId, cardOtherId));
	}

	@GetMapping("/card/neusoftMemberBalance")
	@ApiOperation(value = "第三方员工卡余额查询", notes = "第三方员工卡余额查询")
	public ResponseData<GetBalanceResponse> neusoftMemberBalance(
			@RequestParam(value = "mcode", defaultValue = "", required = false) String mcode,
			@RequestParam(value = "sign", required = false) String sign,
			@RequestParam(value = "memberCardNo", defaultValue = "", required = false) String memberCardNo,
			@RequestParam(value = "nonce", defaultValue = "", required = false) String nonce,
			@RequestParam(value = "timestamp", defaultValue = "", required = false) String timestamp) {

		Map signMapData = getSignMapData(mcode, memberCardNo, nonce, timestamp, sign);
		if (!SignUtils.isSignatureValid(signMapData, CardTradeConstants.SIGN_KTY)) {
			throw new BusinessCommonException(CardErrorCode.CARK_MCH_SIGN_VALIDATE_ERROR);
		}
		val response = new GetBalanceResponse();
		//long balance = cardService.getCardBalance(memberCardNo, null, null);
		Card card = cardService.getSingleCard(memberCardNo,null, null, null, null, null);
		if(card == null) {
			throw new BusinessCommonException(CardErrorCode.CARD_NOT_EXIST);
		}
		response.setBalance(card.getCardBalance());
		response.setMemberName(card.getCardAnotherId());
		return new ResponseData<>(response);
	}

	private Map getSignMapData(String mcode, String memberCardNo, String nonce, String timestamp, String sign) {
		Map<String, String> data = new HashMap();
		data.put("mcode",mcode);
		data.put("memberCardNo",memberCardNo);
		data.put("nonce",nonce);
		data.put("timestamp",timestamp);
		data.put("sign",sign);
		return data;
	}

	@GetMapping("/cardInfo")
	@ApiOperation(value = "POS端卡信息查询接口", notes = "卡信息查询接口")
	public ResponseData<GetCardInfoResponse> cardInfo(
			@RequestParam(value = "cardNum", defaultValue = "", required = false) String cardNum,
			@RequestParam(value = "cardAnotherId", required = false) String cardAnotherId,
			@RequestParam(value = "cardOtherId", defaultValue = "", required = false) String cardOtherId,
			@RequestParam(value = "sn", required = false) String sn) {
		List<Card> cards;
		if(StringUtils.isEmpty(sn)) {
			Integer orgId = RequestHeaderUtil.getOrgId();
			if(null == orgId) {
				throw new BusinessCommonException(CardErrorCode.NO_STORE_PROVIDED);
			}

			Integer storeId = null;
			if(null != RequestHeaderUtil.getStoreIds() && RequestHeaderUtil.getStoreIds().size() > 0) {
				storeId = RequestHeaderUtil.getStoreIds().get(0);
			}
			cards = cardService.getCard(cardNum,cardAnotherId,cardOtherId, null, orgId, storeId);
		} else {
			cards = cardService.getCard(cardNum,cardAnotherId,cardOtherId, sn, null, null);
		}
		if(cards.size() == 0) {
			throw new BusinessCommonException(CardErrorCode.CARD_NOT_EXIST);
		}
		GetCardInfoResponse response = new GetCardInfoResponse();
		List<GetCardInfoResponse.CardInfo> CardInfoList = new ArrayList<GetCardInfoResponse.CardInfo>();
		for(Card card:cards) {
			GetCardInfoResponse.CardInfo cardInfo = new GetCardInfoResponse.CardInfo();
			BeanUtils.copyProperties(card, cardInfo);
			CardInfoList.add(cardInfo);
		}
		response.setCardInfoList(CardInfoList);
		BeanUtils.copyProperties(CardInfoList.get(0), response);

		return new ResponseData<>(response);
	}

	@Transactional
	@PostMapping("/card/update")
	public ResponseData<Integer> updateCard(@RequestBody UpdateCardInfoRequest request) {
		// 卡可操作性验证
		Integer orgId = RequestHeaderUtil.getOrgId();
		if(null == orgId) {
			throw new BusinessCommonException(CardErrorCode.NO_STORE_PROVIDED);
		}
		Integer storeId = null;
		if(null != RequestHeaderUtil.getStoreIds() && RequestHeaderUtil.getStoreIds().size() > 0) {
			storeId = RequestHeaderUtil.getStoreIds().get(0);
		}
		Card originCard = cardService.getCardByPrimaryId(request.getCardId());
		if(originCard.getIsActive() != 1) {
			throw new BusinessCommonException(CardErrorCode.CARD_NOT_EXIST);
		}
		cardService.validateCard(originCard, orgId, storeId);

		return new ResponseData<>(cardService.updateCard(originCard, request));
	}
}
