package com.liquidnet.service.merchant.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.IdentityUtils;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.merchant.dto.param.MerchantSponsorApplyParam;
import com.liquidnet.service.merchant.dto.vo.MerchantSponsorAppliesVo;
import com.liquidnet.service.merchant.service.IMerchantSponsorAppliesService;
import com.liquidnet.service.merchant.service.MerchantRdmService;
import com.liquidnet.service.merchant.util.QueueUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.IntStream;

@Slf4j
@Service
public class MerchantSponsorAppliesServiceImpl implements IMerchantSponsorAppliesService {

    @Autowired
    MerchantRdmService merchantRdmService;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    QueueUtil queueUtils;

    @Override
    public String apply(String uid, MerchantSponsorApplyParam parameter) {
        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> sponsorApplyInsertObjs = CollectionUtil.linkedListObjectArr();

        // 申请主办 vos 上限
        List<MerchantSponsorAppliesVo> sponsorAppliesVos = merchantRdmService.getSponsorAppliesVosByUid(uid);
        if (!CollectionUtils.isEmpty(sponsorAppliesVos)) {
            if (sponsorAppliesVos.size() >= 10) {
                ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13211");
                throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
            }
        }

        LocalDateTime now = LocalDateTime.now();

        // 申请主办 vo
        MerchantSponsorAppliesVo sponsorAppliesVo = MerchantSponsorAppliesVo.getNew();
        BeanUtils.copyProperties(parameter, sponsorAppliesVo);
        sponsorAppliesVo.setSponsorApplyId(IDGenerator.nextSnowId());
        sponsorAppliesVo.setApplyStatus(0);
        sponsorAppliesVo.setApplyType("create");
        sponsorAppliesVo.setReject("");
        sponsorAppliesVo.setUid(uid);
        sponsorAppliesVo.setSponsorId("");
        sponsorAppliesVo.setCreatedAt(now);
        if (parameter.getSkipCompany() > 0) {
            sponsorAppliesVo.setCompanyName("");
            sponsorAppliesVo.setLicenseCode("");
            sponsorAppliesVo.setLicenseImg("");
            sponsorAppliesVo.setLegalName("");
            sponsorAppliesVo.setLegalIdentity("");
            sponsorAppliesVo.setLegalIdentityObverse("");
            sponsorAppliesVo.setLegalIdentityReverse("");
        } else {
            if (sponsorAppliesVo.getCompanyName().isEmpty()
                    || sponsorAppliesVo.getLicenseCode().isEmpty()
                    || sponsorAppliesVo.getLicenseImg().isEmpty()
                    || sponsorAppliesVo.getLegalName().isEmpty()
                    || sponsorAppliesVo.getLegalIdentity().isEmpty()
                    || sponsorAppliesVo.getLegalIdentityObverse().isEmpty()
                    || sponsorAppliesVo.getLegalIdentityReverse().isEmpty()) {
                ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13212");
                throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
            }

            // 身份证检查
            String respStr = IdentityUtils.aliThird(sponsorAppliesVo.getLegalName(), sponsorAppliesVo.getLegalIdentity());;
            JsonNode respJNode = JsonUtils.fromJson(respStr, JsonNode.class);
            if (null == respJNode || !"0".equals(respJNode.get("error_code").asText())) {
                log.info("###法人实名认证失败[{}]", respStr);
                ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13001");
                throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
            }
        }

        // 身份证检查
        String respStr = IdentityUtils.aliThird(sponsorAppliesVo.getContactName(), sponsorAppliesVo.getContactIdentity());;
        JsonNode respJNode = JsonUtils.fromJson(respStr, JsonNode.class);
        if (null == respJNode || !"0".equals(respJNode.get("error_code").asText())) {
            log.info("###联系人实名认证失败[{}]", respStr);
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13002");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }

        // 申请主办 redis
        long s = System.currentTimeMillis();
        merchantRdmService.addSponsorAppliesVoByUid(uid, sponsorAppliesVos, sponsorAppliesVo);
        log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);

        // 申请主办 mongo
        s = System.currentTimeMillis();
        mongoTemplate.insert(sponsorAppliesVo, MerchantSponsorAppliesVo.class.getSimpleName());
        log.debug("#MONGO耗时:{}ms", System.currentTimeMillis() - s);

        // 申请主办 sql
        toMqSqls.add(SqlMapping.get("merchant_sponsor_applies.insert"));
        sponsorApplyInsertObjs.add(new Object[]{
                sponsorAppliesVo.getSponsorApplyId(), sponsorAppliesVo.getApplyStatus(), sponsorAppliesVo.getApplyType(), sponsorAppliesVo.getReject(), sponsorAppliesVo.getUid(),
                sponsorAppliesVo.getName(), sponsorAppliesVo.getLogo(), sponsorAppliesVo.getBackground(), sponsorAppliesVo.getDescription(),
                sponsorAppliesVo.getContactName(), sponsorAppliesVo.getContactIdentity(), sponsorAppliesVo.getContactIdentityObverse(), sponsorAppliesVo.getContactIdentityReverse(), sponsorAppliesVo.getContactEmail(),
                sponsorAppliesVo.getCompanyName(), sponsorAppliesVo.getLicenseCode(), sponsorAppliesVo.getLicenseImg(),
                sponsorAppliesVo.getLegalName(), sponsorAppliesVo.getLegalIdentity(), sponsorAppliesVo.getLegalIdentityObverse(), sponsorAppliesVo.getLegalIdentityReverse(), sponsorAppliesVo.getCreatedAt()
        });

        // mq
        s = System.currentTimeMillis();
        queueUtils.sendMsgByRedis(
                MQConst.MerchantQueue.SQL_MERCHANT_SPONSOR.getKey(),
                SqlMapping.gets(toMqSqls, sponsorApplyInsertObjs)
        );
        log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);

        return sponsorAppliesVo.getSponsorApplyId();
    }

    @Override
    public void applyDel(String uid, String sponsorApplyId) {
        // 查找主办申请，是否存在且已经驳回
        List<MerchantSponsorAppliesVo> sponsorAppliesVos = merchantRdmService.getSponsorAppliesVosByUid(uid);
        if (CollectionUtils.isEmpty(sponsorAppliesVos)) {
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13213");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }
        int idx = IntStream.range(0, sponsorAppliesVos.size())
                .filter(i -> sponsorAppliesVos.get(i).getSponsorApplyId().equals(sponsorApplyId))
                .findFirst()
                .orElse(-1);
        if (idx < 0) {
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13213");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }
        MerchantSponsorAppliesVo sponsorAppliesVo = sponsorAppliesVos.get(idx);
        if (sponsorAppliesVo.getApplyStatus() != 2) {
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13214");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }

        LocalDateTime now = LocalDateTime.now();
        sponsorAppliesVo.setUpdatedAt(now);
        sponsorAppliesVo.setDeletedAt(now);

        // 主办申请 redis
        long s = System.currentTimeMillis();
        merchantRdmService.delSponsorAppliesVoByUid(uid, sponsorAppliesVos, sponsorAppliesVo);
        log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);

        // 主办申请 mongo
        s = System.currentTimeMillis();
        Query query = Query.query(Criteria.where("sponsorApplyId").is(sponsorAppliesVo.getSponsorApplyId()));
        Update update = Update.update("updatedAt", sponsorAppliesVo.getUpdatedAt()).set("deletedAt", sponsorAppliesVo.getDeletedAt());
        mongoTemplate.updateFirst(query, update, MerchantSponsorAppliesVo.class, MerchantSponsorAppliesVo.class.getSimpleName());
        log.debug("#MONGO耗时:{}ms", System.currentTimeMillis() - s);

        // 主办申请 sql
        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> sponsorAppliesUpdateObjs = CollectionUtil.linkedListObjectArr();
        toMqSqls.add(SqlMapping.get("merchant_sponsor_applies.update"));
        sponsorAppliesUpdateObjs.add(new Object[]{
                sponsorAppliesVo.getUpdatedAt(), sponsorAppliesVo.getDeletedAt(), sponsorAppliesVo.getSponsorApplyId()
        });

        // mq
        s = System.currentTimeMillis();
        queueUtils.sendMsgByRedis(
                MQConst.MerchantQueue.SQL_MERCHANT_SPONSOR.getKey(),
                SqlMapping.gets(toMqSqls, sponsorAppliesUpdateObjs)
        );
        log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);
    }

    @Override
    public MerchantSponsorAppliesVo applyInfo(String uid, String sponsorApplyId) {
        // 查找主办申请，是否存在
        List<MerchantSponsorAppliesVo> sponsorAppliesVos = merchantRdmService.getSponsorAppliesVosByUid(uid);
        if (CollectionUtils.isEmpty(sponsorAppliesVos)) {
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13213");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }
        int idx = IntStream.range(0, sponsorAppliesVos.size())
                .filter(i -> sponsorAppliesVos.get(i).getSponsorApplyId().equals(sponsorApplyId))
                .findFirst()
                .orElse(-1);
        if (idx < 0) {
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13213");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }

        return sponsorAppliesVos.get(idx);
    }
}
