package cn.freemud.service;

import cn.freemud.Exceptions.ResponseResult;
import cn.freemud.Exceptions.ServiceException;
import cn.freemud.amp.EnumEmailAlert;
import cn.freemud.base.util.DateUtil;
import cn.freemud.constant.ServiceConstants;
import cn.freemud.entities.dto.BatchQueryActivityInfoRequestDto;
import cn.freemud.entities.dto.BatchQueryActivityInfoResponseDto;
import cn.freemud.entities.dto.GetAppKeyRequestDto;
import cn.freemud.entities.dto.GetAppKeyResponseDto;
import cn.freemud.redis.RedisCache;
import cn.freemud.resposne.SynchronizationOrderResponse;
import cn.freemud.service.thirdparty.CardBinClient;
import cn.freemud.util.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.freemud.application.sdk.api.base.BaseResponse;
import com.freemud.application.sdk.api.constant.ResponseResultEnum;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.membercenter.request.GradeRight;
import com.freemud.application.sdk.api.membercenter.request.SendExperienceRequest;
import com.freemud.application.sdk.api.membercenter.request.SendScoreRequest;
import com.freemud.application.sdk.api.membercenter.request.UpGradeRequest;
import com.freemud.application.sdk.api.membercenter.response.SendExperienceResponse;
import com.freemud.application.sdk.api.membercenter.response.UpGradeResponse;
import com.freemud.application.sdk.api.membercenter.service.MemberCenterService;
import com.freemud.application.sdk.api.membercenter.service.MemberPropertyService;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.OrderInfoReqs;
import com.freemud.application.sdk.api.service.EmailAlertService;
import com.freemud.card.sdk.comm.ActionEnum;
import com.freemud.card.sdk.comm.Finals;
import com.freemud.card.sdk.comm.IUrlConfig;
import com.freemud.card.sdk.comm.SignUtil;
import com.freemud.card.sdk.service.FMCouponService;
import com.freemud.card.sdk.service.MemberProductService;
import com.freemud.card.sdk.vo.comm.GetCouponVo;
import com.freemud.card.sdk.vo.coupon.Active;
import com.freemud.card.sdk.vo.coupon.Code;
import com.freemud.card.sdk.vo.coupon.CreateCouponVo;
import com.freemud.card.sdk.vo.coupon.request.MemberAddCouponVo;
import com.freemud.card.sdk.vo.coupon.response.CouponCreateResponseVo;
import com.freemud.card.sdk.vo.coupon.response.MemberBaseRespVo;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.util.*;

/**
 * All rights Reserved, Designed By www.freemud.cn
 *
 * @version V1.0
 * @Title: ${FILE_NAME}
 * @Package com.freemud.mail.core
 * @Description: $ 经验发放处理类
 * @author: aiqi.gong
 * @date: 2019/3/21 18:37
 * @Copyright: 2018 www.freemud.cn Inc. All rights reserved.
 * 注意：本内容仅限于上海非码科技内部传阅，禁止外泄以及用于其他的商业目
 */
@Service("sendExperienceHandleServiceImpl")
@Slf4j
public class SendExperienceHandleServiceImpl implements SynchronizedScoreAndExpService {

    private static Gson gson = new Gson();

    @Autowired
    private MemberCenterService memberCenterService;
    @Autowired
    private CardBinClient cardBinClient;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IUrlConfig urlConfig;
    @Autowired
    private FMCouponService fmCouponService;
    @Autowired
    private MemberProductService memberProductService;
    @Autowired
    private MemberPropertyService memberPropertyService;
    @Autowired
    private EmailAlertService emailAlertService;

    @Value("${coupon.partner.id}")
    private String couponPartnerId;
    @Value("${coupon.app.id}")
    private String appid;

    /**
     * 积分发送
     *
     * @param uuid
     * @param orderBody
     * @return 处理结果
     */
    @Override
    public SynchronizationOrderResponse synchronizationOrder(String uuid, OrderInfoReqs orderBody) {
        SynchronizationOrderResponse synchronizationOrderResponse = new SynchronizationOrderResponse(Boolean.FALSE, null);

        /**
         *      * 2.1、组装发放对象
         *      * 2.2、调用经验发放接口
         *      * 2.3、调用等级升级接口
         *      * 2.4、判断是否成功升级
         *      * 2.4.1、升级失败返回“无需升级”
         *      * 2.4.2、升级成功，遍历奖励列表
         *      * 2.4.3、根据奖励类型调用各个奖励接口进行奖励发放
         */
        SendExperienceRequest sendExperienceRequest = convent2SendExperienceRequest(orderBody);
        //经验发放
        if (sendExperience(sendExperienceRequest, uuid)) {
            //经验发放成功 调用升级接口
            UpGradeRequest upGradeRequest = convent2upGradeRequest(orderBody);
            if (upGrade(upGradeRequest, uuid, orderBody)) {
                //升级成功 返回成功
                synchronizationOrderResponse.setResult(true);
            }
        }
        return synchronizationOrderResponse;
    }

    private static UpGradeRequest convent2upGradeRequest(OrderInfoReqs orderBean) {
        UpGradeRequest upGradeRequest = new UpGradeRequest();
        upGradeRequest.setPartnerId(orderBean.getPartnerId());
        upGradeRequest.setMemberId(orderBean.getUserId());
        upGradeRequest.setIdempotencyBussinessId(orderBean.getOrderCode());
        upGradeRequest.setIdempotencyBussinessType(ServiceConstants.BUSSINESS_TYPE_3);
        upGradeRequest.setOrderId(orderBean.getOrderCode());
        return upGradeRequest;
    }

    /**
     * 等级升级接口
     *
     * @param upGradeRequest
     * @param uuid
     */
    private boolean upGrade(UpGradeRequest upGradeRequest, String uuid, OrderInfoReqs orderBody) {

        BaseResponse<UpGradeResponse> result = memberCenterService.upGrade(upGradeRequest, uuid);
        if (ResponseResultEnum.SUCCESS.getCode().equals(result.getCode())) {
            //调用成功  判断是否升级成功
            UpGradeResponse upGradeResponse = result.getData();
            if (null != upGradeResponse && ServiceConstants.IS_UP_GRADE == upGradeResponse.getIsUpGrade()) {
                //升级成功  开始发放奖励
                distribution(upGradeResponse.getGradeRights(), uuid, orderBody, upGradeResponse.getRuleCode());
            }
            return true;
        }
        return false;
    }

    /**
     * 奖品发放
     *
     * @param gradeRights
     */
    private void distribution(List<GradeRight> gradeRights, String uuid, OrderInfoReqs orderBody, String ruleCode) {
        if (CollectionUtils.isEmpty(gradeRights)) {
            return;
        }
        List<GradeRight> gradeRightList = new ArrayList<>();
        for (GradeRight gradeRight : gradeRights) {
            if (ServiceConstants.RIGHT_TYPE_1 == gradeRight.getRightType()) {
                //返积分
                if (!sendScore(uuid, orderBody, gradeRight)) {
                    throw new ServiceException(ResponseResult.SEND_EXPERIENCE_FAILED);
                }
            } else if (ServiceConstants.RIGHT_TYPE_2 == gradeRight.getRightType()) {
                //收集发券列表
                gradeRightList.add(gradeRight);
            }
        }
        if (!CollectionUtils.isEmpty(gradeRightList)) {
            //返代金券
            if (!sendCoupon(orderBody, gradeRightList, ruleCode)) {
                throw new ServiceException(ResponseResult.SEND_EXPERIENCE_FAILED);
            }
        }

    }

    /**
     * 券发放
     *
     * @param orderBean
     * @return false 发放失败 true 发放成功
     */
    public boolean sendCoupon(OrderInfoReqs orderBean, List<GradeRight> gradeRightList, String promotionActiveCode) {
        List<CreateCouponVo> createCouponVoList = new ArrayList<>();
        //构造发券请求对象
        for (GradeRight gradeRight : gradeRightList) {
            CreateCouponVo createCouponVo = buildCreateCoupons(queryActivityInfo(orderBean.getPartnerId(),
                    gradeRight.getActivityCode()), orderBean, gradeRight, promotionActiveCode);
            if (createCouponVo != null) {
                createCouponVoList.add(createCouponVo);
            }
        }
        // 构建券
        GetCouponVo getCouponVo = new GetCouponVo();
        getCouponVo.setPartner_id(Integer.valueOf(couponPartnerId));
        getCouponVo.setMerchant_id(Integer.valueOf(orderBean.getPartnerId()));
        getCouponVo.setMobile("18900000000");
        getCouponVo.setMemberId(orderBean.getUserId());
        getCouponVo.setAppSecret(getAppSecret(couponPartnerId));
        getCouponVo.setCoupons(createCouponVoList);
        return getCoupons(getCouponVo, orderBean.getOrderCode());
    }


    private String getAppSecret(String partnerId) {
        // 获取券服务的密钥
        String couponAppSecret = RedisUtil.getCouponAppSecret(partnerId);
        String appSecret = redisCache.getValue(couponAppSecret);
        if (StringUtils.isBlank(appSecret)) {
            GetAppKeyResponseDto getAppKeyResponseDto = cardBinClient.getAppKey(GetAppKeyRequestDto.builder().partnerId(partnerId).appId(appid).build());
            if (Objects.equals(String.valueOf(getAppKeyResponseDto.getStatusCode()), ResponseResultEnum.SUCCESS.getCode())
                    && getAppKeyResponseDto.getData() != null) {
                redisCache.save(couponAppSecret, getAppKeyResponseDto.getData().getAppKey());
                appSecret = getAppKeyResponseDto.getData().getAppKey();
            }
        }
        return appSecret;
    }

    /**
     * 返积分
     *
     * @param uuid
     * @return
     */
    private boolean sendScore(String uuid, OrderInfoReqs orderBean, GradeRight gradeRight) {
        SendScoreRequest sendScoreRequest = new SendScoreRequest();
        sendScoreRequest.setPartnerId(orderBean.getPartnerId());
        sendScoreRequest.setMemberId(orderBean.getUserId());
        sendScoreRequest.setScore(gradeRight.getScoreValue());
        sendScoreRequest.setOperationType(ServiceConstants.SCORE_OPERATION_TYPE_5);
        sendScoreRequest.setIdempotencyBussinessId(orderBean.getOrderCode());
        sendScoreRequest.setIdempotencyBussinessType(ServiceConstants.IDEMPOTENCY_BUSSINESS_TYPE_13);
        sendScoreRequest.setOrgType(3);
        sendScoreRequest.setOrgCode(orderBean.getStoreId());
        BaseResponse result = memberPropertyService.sendScore(sendScoreRequest, uuid);
        if (ResponseResultEnum.SUCCESS.getCode().equals(result.getCode())) {
            return true;
        }
        return false;

    }

    /**
     * 经验发放
     *
     * @param sendExperienceRequest
     * @param uuid
     * @return true 发放成功 false 发放失败
     */
    private boolean sendExperience(SendExperienceRequest sendExperienceRequest, String uuid) {

        BaseResponse<SendExperienceResponse> result = memberCenterService.sendExperience(sendExperienceRequest, uuid);
        if (ResponseResultEnum.SUCCESS.getCode().equals(result.getCode())) {
            return true;
        } else if ("1020".equalsIgnoreCase(result.getCode())) {
            //如果商户没有配置经验值规则，发邮件告知
          /*  emailAlertService.sendEmailAlert(EnumEmailAlert.Description.NoExpRule.getDescription(),
                    "request:"+JSON.toJSONString(sendExperienceRequest)+
                    ",response:"+JSON.toJSONString(result));*/
        }
        return false;
    }

    /**
     * 转换经验发放请求对象
     *
     * @param orderBean
     * @return
     */
    private static SendExperienceRequest convent2SendExperienceRequest(OrderInfoReqs orderBean) {
        SendExperienceRequest sendExperienceRequest = new SendExperienceRequest();
        sendExperienceRequest.setPartnerId(orderBean.getPartnerId());
        sendExperienceRequest.setMemberId(orderBean.getUserId());
        sendExperienceRequest.setAmount(orderBean.getSettlementAmount() == null ? 0 : orderBean.getSettlementAmount().intValue());
        sendExperienceRequest.setChangeType(ServiceConstants.CHANGE_TYPE_1);
        sendExperienceRequest.setOperationType(ServiceConstants.OPERATION_TYPE_1);
        sendExperienceRequest.setOrderId(orderBean.getOrderCode());
        sendExperienceRequest.setIdempotencyBussinessType(ServiceConstants.BUSSINESS_TYPE_2);
        sendExperienceRequest.setIdempotencyBussinessId(orderBean.getOrderCode());
        return sendExperienceRequest;
    }

    /**
     * @param getCouponVo
     * @return false 发放失败 true 发放成功
     */
    private boolean getCoupons(GetCouponVo getCouponVo, String oid) {
        //组装发码VO
        List<CreateCouponVo> couponList = getCouponVo.getCoupons();
        List<MemberAddCouponVo.Coupons> addCoupons = new ArrayList<>();
        for (CreateCouponVo couponVo : couponList) {
            MultiValueMap<String, String> params = getFMCouponCreateMap(getCouponVo, couponVo);
            //进行发码
            StringBuilder urlBuilder = new StringBuilder();
            urlBuilder.append(urlConfig.getCouponOnlineUrl())
                    .append(ActionEnum.COUPON_ONLINE.getAction());
            CouponCreateResponseVo resultCode = fmCouponService.createCode(params, urlBuilder.toString());
            if (resultCode.getResult() == 0) {
                //创建失败
                continue;
            }

            resultCode.getCodes().forEach(eachCode -> {
                MemberAddCouponVo.Coupons addCoupon = getMemberAddCouponVo(eachCode, couponVo, oid);
                addCoupons.add(addCoupon);
            });
        }
        //插入卡包
        MemberAddCouponVo memberAddCouponVo = new MemberAddCouponVo();
        memberAddCouponVo.setMemberId(getCouponVo.getMemberId());
        memberAddCouponVo.setCoupons(addCoupons);
        memberAddCouponVo.setPartnerId(getCouponVo.getMerchant_id().toString());
        MemberBaseRespVo memberResp = memberProductService.receiveMemberCoupon(memberAddCouponVo);
        if (!memberResp.getCode().equals(ResponseResultEnum.SUCCESS.getCode())) {
            //失败了
            return false;
        }
        return true;
    }


    private MemberAddCouponVo.Coupons getMemberAddCouponVo(Code eachCode, CreateCouponVo couponVo, String oid) {
        MemberAddCouponVo.Coupons addCoupon = new MemberAddCouponVo.Coupons();
        addCoupon.setCouponCode(eachCode.getCode());
        addCoupon.setActivityCode(couponVo.getActive_code());
        addCoupon.setEncodeCouponCode(eachCode.getEnCode());
        addCoupon.setCouponChannel(couponVo.getSourceFlag());
        addCoupon.setCouponName(couponVo.getActive_name());
        addCoupon.setCouponType(couponVo.getCouponType());
        addCoupon.setStartTime(couponVo.getValid_start());
        addCoupon.setEndTime(couponVo.getValid_ends());
        addCoupon.setPromotionCode(couponVo.getPromotionActiveCode());
        addCoupon.setPromotionType(ServiceConstants.PROMOTION_TYPE_2);
        addCoupon.setSourceCode(oid);
        return addCoupon;
    }

    /**
     * 构造请求json字符串map
     *
     * @param getCouponVo
     * @param couponVo
     * @return
     */
    private MultiValueMap<String, String> getFMCouponCreateMap(GetCouponVo getCouponVo, CreateCouponVo couponVo) {
        MultiValueMap<String, String> couponOnlineMap = new LinkedMultiValueMap<>();
        couponOnlineMap.add(Finals.PARTNER_ID, getCouponVo.getPartner_id().toString());
        couponOnlineMap.add(Finals.MERCHANT_ID, getCouponVo.getMerchant_id().toString());
        couponOnlineMap.add(Finals.ORDER_ID, couponVo.getOrder_id());
        couponOnlineMap.add(Finals.ACTIVECODE, couponVo.getActive_code());
        couponOnlineMap.add(Finals.VALID_ENDS, couponVo.getValid_ends());
        couponOnlineMap.add(Finals.VALID_START, couponVo.getValid_start());
        couponOnlineMap.add(Finals.MOBILE, getCouponVo.getMobile());
        if (couponVo.getSms_template() != null) {
            couponOnlineMap.add(Finals.SMS_TEMPLATE, couponVo.getSms_template());
        }
        if (StringUtils.isNotEmpty(couponVo.getValid_days())) {
            couponOnlineMap.add(Finals.VALID_DAYS, couponVo.getValid_days());
        }
        couponOnlineMap.add(Finals.TITLE, couponVo.getTitle());
        couponOnlineMap.add(Finals.TIMESTAMP, couponVo.getTimestamp());
        couponOnlineMap.add(Finals.NUMBER, couponVo.getNumber().toString());
        couponOnlineMap.add(Finals.ACTION, getCouponVo.getAction());
        if (StringUtils.isNotEmpty(couponVo.getParams())) {
            couponOnlineMap.add(Finals.PARAMS, couponVo.getParams());
        }
        couponOnlineMap.add(Finals.FLAG, StringUtils.isEmpty(getCouponVo.getFlag()) ? ServiceConstants.DEFAULT_FLAG : getCouponVo.getFlag());

        Map<String, String> signMap = couponOnlineMap.toSingleValueMap();
        String sign = SignUtil.createMD5Sign(signMap, getCouponVo.getAppSecret());
        couponOnlineMap.add(Finals.SIGN, sign);
        return couponOnlineMap;
    }


    public CreateCouponVo buildCreateCoupons(Active active, OrderInfoReqs orderBody, GradeRight gradeRight, String promotionActiveCode) {

        // 不再可领取有效期范围内直接过
        if (null == active || active.getStartDate() == null || active.getEndDate() == null) {
            return null;
        }
        Long now = System.currentTimeMillis();

        if (now < Long.valueOf(active.getStartDate()) || now > Long.valueOf(active.getEndDate())) {
            return null;
        }
        // 券活动状态不是已启用得过
        if (!Objects.equals(active.getState(), ServiceConstants.ACTIVE_STATE_1)) {
            return null;
        }
        CreateCouponVo createCouponVo = new CreateCouponVo();
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        createCouponVo.setOrder_id(uuid);
        createCouponVo.setNumber(gradeRight.getCouponNum());
        createCouponVo.setTitle(gradeRight.getCouponName());
        createCouponVo.setState(0);
        createCouponVo.setTimestamp(DateUtil.convert2Str(new Date(), DateUtil.FORMAT_YYYY_MM_DD_HHMMSS));
        createCouponVo.setActive_code(gradeRight.getActivityCode());
        createCouponVo.setActive_name(gradeRight.getCouponName());
        createCouponVo.setSourceFlag(ServiceConstants.SOURCE_FLAG);
        createCouponVo.setRemark(gradeRight.getCouponName());
        createCouponVo.setPromotionActiveCode(promotionActiveCode);
        createCouponVo.setCouponType(String.valueOf(gradeRight.getCouponType()));

        if (active.getEffectiveStart() != null && active.getEffectiveEnd() != null) {
            // 根据有效期来计算
            createCouponVo.setValid_start(DateUtil.convert2Str(active.getEffectiveStart(), DateUtil.FORMAT_YYYY_MM_DD_HHMMSS));
            createCouponVo.setValid_ends(DateUtil.convert2Str(active.getEffectiveEnd(), DateUtil.FORMAT_YYYY_MM_DD_HHMMSS));
        } else {
            // 根据固定时长来计算 天来计算
            int delayTimes = active.getFromDayEffective() != null ? active.getFromDayEffective() : 0;
            // 有效期为0  默认传1天，做兼容处理
            int validityPeriod = active.getEffective() != null ? active.getEffective() : 1;
            createCouponVo.setValid_start(DateUtil.convert2Str(DateUtil.addDays(new Date(), delayTimes), DateUtil.FORMAT_YYYY_MM_DD_HHMMSS));
            createCouponVo.setValid_ends(DateUtil.convert2Str(DateUtil.addDays(new Date(), (delayTimes + validityPeriod - 1)), ServiceConstants.FORMAT_YYYY_DD_23_59_59));
        }
        return createCouponVo;
    }

    /**
     * 查询券详情
     */
    private Active queryActivityInfo(String partnerId, String activeCode) {

        String appSecret = getAppSecret(partnerId);
        BatchQueryActivityInfoRequestDto requestDto = new BatchQueryActivityInfoRequestDto();
        requestDto.setActiveCode(Arrays.asList(activeCode));
        // 书写逻辑
        requestDto.setPartnerId(Integer.valueOf(partnerId));
        String sign = SignUtil.createMD5Sign(requestDto, appSecret);
        requestDto.setSign(sign);
        BatchQueryActivityInfoResponseDto batchQueryActivityInfoResponseDto = cardBinClient.batchQueryActivityInfo(requestDto);
        ApiLog.info("发放经验值查询券详情{},{},/batchQueryActivityInfo",JSON.toJSONString(requestDto),JSON.toJSONString(batchQueryActivityInfoResponseDto));
        if (Objects.equals(batchQueryActivityInfoResponseDto.getStatusCode(), ServiceConstants.RESPONSE_SUCCESS_0_STR) && !CollectionUtils.isEmpty(batchQueryActivityInfoResponseDto.getActivities())) {
            return batchQueryActivityInfoResponseDto.getActivities().get(0);
        }
        return null;
    }

}
