package com.jsowell.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.Payment;
import com.jsowell.adapay.common.CreateAdaPaymentParam;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.constant.Constants;
import com.jsowell.common.core.page.PageResponse;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.enums.TitleTypeEnum;
import com.jsowell.common.enums.uniapp.BalanceChangesEnum;
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
import com.jsowell.common.enums.ykc.ScenarioEnum;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.AdapayUtil;
import com.jsowell.common.util.JWTUtils;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.id.IdUtils;
import com.jsowell.common.util.id.SnowflakeIdWorker;
import com.jsowell.pile.domain.MemberBasicInfo;
import com.jsowell.pile.domain.MemberInvoiceTitle;
import com.jsowell.pile.domain.MemberPlateNumberRelation;
import com.jsowell.pile.domain.MemberWalletInfo;
import com.jsowell.pile.domain.PileAuthCard;
import com.jsowell.pile.dto.BindingCarNoDTO;
import com.jsowell.pile.dto.BindingCardDTO;
import com.jsowell.pile.dto.InvoiceTitleDTO;
import com.jsowell.pile.dto.MemberRegisterAndLoginDTO;
import com.jsowell.pile.dto.MemberRegisterDTO;
import com.jsowell.pile.dto.PaymentScenarioDTO;
import com.jsowell.pile.dto.UniAppQueryMemberBalanceDTO;
import com.jsowell.pile.dto.WechatLoginDTO;
import com.jsowell.pile.dto.WeixinPayDTO;
import com.jsowell.pile.service.IMemberBasicInfoService;
import com.jsowell.pile.service.IMemberInvoiceTitleService;
import com.jsowell.pile.service.IMemberPlateNumberRelationService;
import com.jsowell.pile.service.IPileAuthCardService;
import com.jsowell.pile.service.IPileMerchantInfoService;
import com.jsowell.pile.transaction.dto.MemberTransactionDTO;
import com.jsowell.pile.transaction.service.TransactionService;
import com.jsowell.pile.vo.MemberPlateNumberVO;
import com.jsowell.pile.vo.uniapp.InvoiceTitleVO;
import com.jsowell.pile.vo.uniapp.MemberVO;
import com.jsowell.pile.vo.uniapp.MemberWalletLogVO;
import com.jsowell.wxpay.service.WxAppletRemoteService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

@Service
public class MemberService {
	private final Logger log = LoggerFactory.getLogger(this.getClass());

	@Autowired
	private RedisCache redisCache;

	@Autowired
	private TransactionService transactionService;

	@Autowired
	private IMemberBasicInfoService memberBasicInfoService;

	@Autowired
	private IPileMerchantInfoService pileMerchantInfoService;

	@Autowired
	private WxAppletRemoteService wxAppletRemoteService;

	@Autowired
	private IMemberPlateNumberRelationService memberPlateNumberRelationService;

	@Autowired
	private IPileAuthCardService pileAuthCardService;

	@Autowired
	private IMemberInvoiceTitleService memberInvoiceTitleService;

	@Autowired
	private OrderService orderService;

	@Value("${adapay.appId}")
	private String ADAPAY_APP_ID;

	@Value("${adapay.callback}")
	private String ADAPAY_CALLBACK_URL;

	/**
	 * 校验短信验证码
	 * @param dto
	 */
	public void checkVerificationCode(MemberRegisterAndLoginDTO dto) {
		// 取出缓存中的验证码进行对比，如果缓存中没有，则超时
		String captchaCode = redisCache.getCacheObject(CacheConstants.SMS_VERIFICATION_CODE_KEY + dto.getMobileNumber());
		if (StringUtils.isEmpty(captchaCode)) {
			throw new BusinessException(ReturnCodeEnum.CODE_VERIFICATION_CODE_TIMEOUT_ERROR);
		}
		// 如果缓存中有，但与实际不一致，则为验证码错误
		if (!StringUtils.equals(captchaCode, dto.getVerificationCode())) {
			throw new BusinessException(ReturnCodeEnum.CODE_VERIFICATION_CODE_ERROR);
		}
	}

	/**
	 * 短信验证码登录注册
	 * @param dto
	 * @return
	 */
	public String memberRegisterAndLogin(MemberRegisterAndLoginDTO dto) {
		// 校验短信验证码 两种情况不能通过校验，1-验证码错误；2-超时 验证码10分钟有效
		checkVerificationCode(dto);
		String merchantId = "";
		return memberRegisterAndLogin(dto.getMobileNumber(), dto.getMerchantId(), dto.getOpenId());
	}

	/**
	 * 公共登陆注册方法
	 * @param phoneNumber 手机号
	 * @param merchantId 商户id
	 * @return token返给前端
	 */
	private String memberRegisterAndLogin(String phoneNumber, String merchantId, String openId) {
		if (StringUtils.isBlank(phoneNumber)) {
			throw new BusinessException(ReturnCodeEnum.CODE_GET_MOBILE_NUMBER_BY_CODE_ERROR);
		}
		// if (Objects.isNull(merchantId)) {
		// 	throw new BusinessException(ReturnCodeEnum.CODE_GET_MERCHANT_ID_BY_APP_ID_ERROR);
		// }
		// 查询手机号码是否注册过
		MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumberAndMerchantId(phoneNumber, merchantId);
		if (Objects.isNull(memberBasicInfo)) {
			// 不存在则新增数据
			String memberId = generateNewMemberId();
			memberBasicInfo = new MemberBasicInfo();
			memberBasicInfo.setStatus(Constants.ONE);
			memberBasicInfo.setMemberId(memberId);
			memberBasicInfo.setNickName("会员" + memberId);
			memberBasicInfo.setMobileNumber(phoneNumber);
			memberBasicInfo.setMerchantId(Long.valueOf(merchantId));
			memberBasicInfo.setOpenId(openId);

			// 首次新建会员，同时新建会员钱包
			MemberWalletInfo memberWalletInfo = MemberWalletInfo.builder().memberId(memberId).build();
			MemberTransactionDTO memberTransactionDTO = MemberTransactionDTO.builder()
					.memberBasicInfo(memberBasicInfo)
					.memberWalletInfo(memberWalletInfo)
					.build();
			transactionService.createMember(memberTransactionDTO);
		} else {
			if (StringUtils.isBlank(memberBasicInfo.getOpenId()) && StringUtils.isNotBlank(openId)) {
				memberBasicInfo.setOpenId(openId);
				memberBasicInfoService.updateMemberBasicInfo(memberBasicInfo);
			}
		}
		// 服务器生成token返给前端
		String memberToken = JWTUtils.createMemberToken(memberBasicInfo.getMemberId(), memberBasicInfo.getNickName());
		// log.info("memToken:{}", memberToken);
		return memberToken;
	}

	private String generateNewMemberId() {
		while (true) {
			String memberId = IdUtils.getMemberId();
			// 通过memberId查询是否已经存在
			MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(memberId);
			if (memberVO == null) {
				return memberId;
			}
		}
	}

	/**
	 * 微信一键登录
	 * @param dto
	 */
	public String wechatLogin(WechatLoginDTO dto) {
		// 通过微信传的code获取手机号码
		String mobileNumber = wxAppletRemoteService.getMobileNumberByCode(dto.getCode());
		if (StringUtils.isBlank(mobileNumber)) {
			throw new BusinessException(ReturnCodeEnum.CODE_GET_MOBILE_NUMBER_BY_CODE_ERROR);
		}
		// 通过appid获取运营商id
		String merchantId = pileMerchantInfoService.getMerchantIdByAppId(dto.getAppId());
		// if (Objects.isNull(merchantId)) {
		// 	throw new BusinessException(ReturnCodeEnum.CODE_GET_MERCHANT_ID_BY_APP_ID_ERROR);
		// }
		// 通过code获取openId
		String openId = "";
		try {
			openId = getOpenIdByCode(dto.getOpenIdCode());
		} catch (Exception e) {
			log.error("getOpenIdByCode发生异常", e);
		}
		// 查询手机号码是否注册过
		return memberRegisterAndLogin(mobileNumber, merchantId, openId);
	}

	/**
	 * 获取openId
	 * @param code
	 * @return
	 */
	public String getOpenIdByCode(String code) {
		return wxAppletRemoteService.getOpenIdByCode(code);
	}

	/**
	 * 处理用户信息
	 *
	 * @param memberId
	 * @param dto      用户个人信息
	 */
	public void handleUserInfo(String memberId, MemberRegisterDTO dto) {
		// 通过用户手机号查询数据库，如果数据库中存在，则更新
		// MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumber(dto.getMobileNumber());
		MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMemberId(memberId);
		if (Objects.nonNull(memberBasicInfo)) {
			if (StringUtils.isNotBlank(dto.getAvatarUrl())) {
				memberBasicInfo.setAvatarUrl(dto.getAvatarUrl());
			}
			if (StringUtils.isNotBlank(dto.getMobileNumber())) {
				memberBasicInfo.setMobileNumber(dto.getMobileNumber());
			}
			if (StringUtils.isNotBlank(dto.getNickName())) {
				memberBasicInfo.setNickName(dto.getNickName());
			}
			memberBasicInfoService.updateMemberBasicInfo(memberBasicInfo);
		}

	}

	/**
	 * 通过memberToken获取用户账户信息
	 *
	 * @param memberId
	 * @return
	 */
    public MemberVO getMemberInfoByMemberId(String memberId) {
		MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(memberId);

		return memberVO;
    }

	/**
	 * 查询用户账户余额变动信息
	 *
	 * @param dto
	 */
	public PageResponse getMemberBalanceChanges(UniAppQueryMemberBalanceDTO dto) {

		// 获取分页信息以及memberId
		int pageNum = dto.getPageNum() == 0 ? 1 : dto.getPageNum();
		int pageSize = dto.getPageSize() == 0 ? 10 : dto.getPageSize();
		String memberId = dto.getMemberId();
		String type = dto.getType();

		if (!StringUtils.equals("1", type) && !StringUtils.equals("2", type)) {
			type = "";
		}
		// 分页
		PageHelper.startPage(pageNum, pageSize);
		List<MemberWalletLogVO> list = memberBasicInfoService.getMemberBalanceChanges(memberId, type);
		PageInfo<MemberWalletLogVO> pageInfo = new PageInfo<>(list);

		for (MemberWalletLogVO walletLogVO : pageInfo.getList()) {
			String subType = walletLogVO.getSubType();
			String subTypeValue = BalanceChangesEnum.getValueByCode(subType);
			if (StringUtils.isNotBlank(subTypeValue)) {
				walletLogVO.setSubType(subTypeValue);
			}
			// walletLogVO.setTotalAccountAmount(walletLogVO.getPrincipalBalance().add(walletLogVO.getGiftBalance()));
		}
		PageResponse pageResponse = PageResponse.builder()
				.pageSize(pageSize)
				.pageNum(pageNum)
				.list(pageInfo.getList())
				.pages(pageInfo.getPages())
				.total(pageInfo.getTotal())
				.build();
		return pageResponse;
	}

	/**
	 * 用户绑定车牌号
	 * @param dto
	 */
	public void memberBindingCarNo(BindingCarNoDTO dto){
		// 校验短信验证码
		MemberRegisterAndLoginDTO registerAndLoginDTO = MemberRegisterAndLoginDTO.builder()
				.mobileNumber(dto.getPhoneNumber())
				.verificationCode(dto.getVerificationCode())
				.build();
		checkVerificationCode(registerAndLoginDTO);

		// 判断当前车牌号是否已经绑定
		MemberPlateNumberRelation relation = new MemberPlateNumberRelation();
		relation.setMemberId(dto.getMemberId());
		relation.setLicensePlateNumber(dto.getCarNo());
		List<MemberPlateNumberRelation> list = memberPlateNumberRelationService.selectMemberPlateNumberRelationList(relation);
		if (CollectionUtils.isNotEmpty(list)) {
			// 不为空说明该用户绑定过此车牌号
			throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARNO_HAS_BEEN_BINDING);
		}
		relation.setPhoneNumber(dto.getPhoneNumber());
		if (StringUtils.isNotBlank(dto.getVinCode())) {
			relation.setVinCode(dto.getVinCode().toUpperCase(Locale.ROOT));
			relation.setVinStatus("1"); // 1-正常使用
		}
		memberPlateNumberRelationService.insertMemberPlateNumberRelation(relation);
	}

	/**
	 * 用户绑定鉴权卡
	 * @param dto
	 */
	public int memberBindCard(BindingCardDTO dto){
		// 校验短信验证码
		MemberRegisterAndLoginDTO registerAndLoginDTO = MemberRegisterAndLoginDTO.builder()
				.mobileNumber(dto.getPhoneNumber())
				.verificationCode(dto.getVerificationCode())
				.build();
		checkVerificationCode(registerAndLoginDTO);
		// 判断当前鉴权卡是否被绑定过
		PileAuthCard pileAuthCardInfo = pileAuthCardService.selectCardInfoByLogicCard(dto.getLogicCard());
		if (pileAuthCardInfo == null){
			// 为空说明没查到此卡信息
			throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_NO_INFO);
		}
		if (StringUtils.isNotBlank(pileAuthCardInfo.getMemberId())) {
			// memberId 不为空，说明此卡已被绑定
			throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_BEEN_BINDING);
		}
		if (!StringUtils.equals(pileAuthCardInfo.getSecretKey(), dto.getSecretKey().toUpperCase(Locale.ROOT))) {
			// 密钥不一致，不能绑定
			throw new BusinessException(ReturnCodeEnum.CODE_SECRET_KEY_NOT_SAME);
		}
		PileAuthCard authCard = PileAuthCard.builder()
				.memberId(dto.getMemberId())
				.status("1") // 1-正常使用
				.createBy(dto.getMemberId())
				.id(pileAuthCardInfo.getId())
				.build();
		return pileAuthCardService.updatePileAuthCard(authCard);
	}

	/**
	 * 用户解绑鉴权卡
	 * @param dto
	 * @return
	 */
	public int memberUnbindCard(BindingCardDTO dto) {
		// 校验短信验证码
		MemberRegisterAndLoginDTO registerAndLoginDTO = MemberRegisterAndLoginDTO.builder()
				.mobileNumber(dto.getPhoneNumber())
				.verificationCode(dto.getVerificationCode())
				.build();
		// checkVerificationCode(registerAndLoginDTO);
		// 校验身份信息
		PileAuthCard authCard = PileAuthCard.builder()
				.logicCard(dto.getLogicCard())
				.memberId(dto.getMemberId())
				.build();
		PileAuthCard pileAuthCardInfo = pileAuthCardService.selectPileAuthCardInfo(authCard);
		if (pileAuthCardInfo == null){
			// 为空说明没查到此卡信息
			throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_NO_INFO);
		}
		// 解绑鉴权卡
		return pileAuthCardService.unBindingCard(authCard);
	}

	public List<InvoiceTitleVO> queryMemberInvoiceTitles(String memberId) {
		List<InvoiceTitleVO> resultList = Lists.newArrayList();
		List<MemberInvoiceTitle> memberInvoiceTitles = memberInvoiceTitleService.selectMemberInvoiceTitleList(memberId);
		if (CollectionUtils.isEmpty(memberInvoiceTitles)) {
			return resultList;
		}
		for (MemberInvoiceTitle memberInvoiceTitle : memberInvoiceTitles) {
			String reception = StringUtils.isNotEmpty(memberInvoiceTitle.getEmail())
					? memberInvoiceTitle.getEmail()
					: memberInvoiceTitle.getPhoneNumber();
			resultList.add(
					InvoiceTitleVO.builder()
							.titleId(memberInvoiceTitle.getId() + "")
							.titleName(memberInvoiceTitle.getName())
							.titleType(TitleTypeEnum.getLabel(memberInvoiceTitle.getTitleType()))
							.taxId(memberInvoiceTitle.getTaxId())
							.unitAddress(memberInvoiceTitle.getUnitAddress())
							.phoneNumber(memberInvoiceTitle.getPhoneNumber())
							.email(memberInvoiceTitle.getEmail())
							.reception(reception)
							.bankName(memberInvoiceTitle.getBankName())
							.bankAccountNumber(memberInvoiceTitle.getBankAccountNumber())
							.defaultFlag(memberInvoiceTitle.getDefaultFlag())
							.build()
			);
		}
		return resultList;
	}

	public void createMemberInvoiceTitle(InvoiceTitleDTO dto) {
		MemberInvoiceTitle title = new MemberInvoiceTitle();
		BeanUtils.copyProperties(dto, title);
		title.setName(dto.getTitleName());
		if (StringUtils.isEmail(dto.getReception())) {
			title.setEmail(dto.getReception());
		} else {
			title.setPhoneNumber(dto.getReception());
		}
		int i = memberInvoiceTitleService.insertMemberInvoiceTitle(title);
		// log.info("新增{}条发票抬头", i);
	}

	public void updateMemberInvoiceTitle(InvoiceTitleDTO dto) {
		MemberInvoiceTitle title = new MemberInvoiceTitle();
		BeanUtils.copyProperties(dto, title);
		title.setId(Long.valueOf(dto.getTitleId()));
		title.setName(dto.getTitleName());
		if (StringUtils.isEmail(dto.getReception())) {
			title.setEmail(dto.getReception());
		} else {
			title.setPhoneNumber(dto.getReception());
		}
		int i = memberInvoiceTitleService.updateMemberInvoiceTitle(title);
	}

	/**
	 * 删除会员发票抬头
	 * @param dto
	 */
	public void deleteMemberInvoiceTitle(InvoiceTitleDTO dto) {
		memberInvoiceTitleService.deleteMemberInvoiceTitleById(Long.valueOf(dto.getTitleId()));
	}

	public Map<String, Object> rechargeBalance(WeixinPayDTO dto) throws Exception {
		PaymentScenarioDTO paymentScenarioDTO = new PaymentScenarioDTO();
		paymentScenarioDTO.setType(ScenarioEnum.BALANCE.getValue());
		paymentScenarioDTO.setMemberId(dto.getMemberId());
		dto.setAttach(JSONObject.toJSONString(paymentScenarioDTO));
		dto.setDescription("会员充值余额");
		return orderService.weixinPayV3(dto);
	}

	/**
	 * 使用汇付支付充值余额
	 * @param dto
	 * @return
	 * @throws Exception
	 */
	public Map<String, Object> rechargeBalanceWithAdapay(WeixinPayDTO dto) throws Exception {
		// 封装对象
		CreateAdaPaymentParam createAdaPaymentParam = new CreateAdaPaymentParam();
		createAdaPaymentParam.setOrder_no(SnowflakeIdWorker.getSnowflakeId());
		createAdaPaymentParam.setPay_amt(AdapayUtil.formatAmount(dto.getAmount()));
		createAdaPaymentParam.setApp_id(ADAPAY_APP_ID); // 移动到配置文件中
		createAdaPaymentParam.setPay_channel("wx_lite"); // todo 如果以后有支付宝等别的渠道，这里需要做修改，判断是什么渠道的请求
		createAdaPaymentParam.setGoods_title("余额");
		createAdaPaymentParam.setGoods_desc("会员充值余额");
		// createAdaPaymentParam.setDescription("充电费用3");
		createAdaPaymentParam.setExpend(JSONObject.toJSONString( ImmutableMap.of("open_id", dto.getOpenId())));
		//异步通知地址，url为http/https路径，服务器POST回调，URL 上请勿附带参数
		createAdaPaymentParam.setNotify_url(ADAPAY_CALLBACK_URL);
		Map<String, String> map = Maps.newHashMap();
		map.put("type", ScenarioEnum.BALANCE.getValue());
		map.put("memberId", dto.getMemberId());
		createAdaPaymentParam.setDescription(JSON.toJSONString(map));
		try {
			log.info("创建汇付支付参数:{}", JSONObject.toJSONString(createAdaPaymentParam));
			Map<String, Object> response = Payment.create(BeanMap.create(createAdaPaymentParam));
			log.info("创建汇付支付参数反参:{}", JSONObject.toJSONString(response));
			if (response != null && !response.isEmpty()) {
				JSONObject jsonObject = JSONObject.parseObject(response.get("expend").toString());
				JSONObject pay_info = jsonObject.getJSONObject("pay_info");
				Map<String, Object> resultMap = JSONObject.parseObject(pay_info.toJSONString(), new TypeReference<Map<String, Object>>() {});
				return resultMap;
			}
		} catch (BaseAdaPayException e) {
			log.error("汇付-获取支付对象发生异常", e);
		}
		return null;
	}


}
