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

import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.PagedResult;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.merchant.dto.param.MerchantFieldApplyParam;
import com.liquidnet.service.merchant.dto.vo.MerchantFieldAppliesVo;
import com.liquidnet.service.merchant.dto.vo.MerchantFieldsVo;
import com.liquidnet.service.merchant.service.IMerchantFieldsAppliesService;
import com.liquidnet.service.merchant.service.MerchantRdmService;
import com.liquidnet.service.merchant.util.ObjectUtil;
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.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
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.regex.Pattern;

@Slf4j
@Service
public class MerchantFieldsAppliesServiceImpl implements IMerchantFieldsAppliesService {

    @Autowired
    MerchantRdmService merchantRdmService;

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    QueueUtil queueUtils;

    @Override
    public PagedResult<MerchantFieldsVo> search(String name, int page, int size) {
        Query query = new Query();
        String regex = String.format("%s%s%s", "^.*", name, ".*$");
        Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        query.addCriteria(Criteria.where("name").regex(pattern));
        query.addCriteria(Criteria.where("isOnline").is(1));

        long count = mongoTemplate.count(query, MerchantFieldsVo.class, MerchantFieldsVo.class.getSimpleName());

        PagedResult<MerchantFieldsVo> pagedResult = ObjectUtil.getMerchantFieldsVoPagedResult();
        if (count > 0) {
            query.fields().include("fieldId").include("isOnline").include("claimStatus").include("name");

            Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt"));
            query.with(pageable);
            List<MerchantFieldsVo> fieldsVoList = mongoTemplate.find(query, MerchantFieldsVo.class, MerchantFieldsVo.class.getSimpleName());

            pagedResult.setList(fieldsVoList).setTotal(count, size);
        }

        return pagedResult;
    }

    @Override
    public String apply(String uid, MerchantFieldApplyParam parameter) {
        LocalDateTime now = LocalDateTime.now();

        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> fieldUpdateObjs = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> fieldApplyInsertObjs = CollectionUtil.linkedListObjectArr();

        // 若认领，查询验证场地
        MerchantFieldsVo fieldsVo = null;
        if (!parameter.getFieldId().isEmpty()) {
            fieldsVo = merchantRdmService.getFieldsVoByFieldId(parameter.getFieldId());
            if (null == fieldsVo) {
                ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13001");
                throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
            }
            if (0 != fieldsVo.getClaimStatus()) {
                ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13002");
                throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
            }
        }

        // 申请场地 vos 上限
        List<MerchantFieldAppliesVo> fieldsAppliesVos = merchantRdmService.getFieldsAppliesVosByUid(uid);
        if (!CollectionUtils.isEmpty(fieldsAppliesVos)) {
            if (fieldsAppliesVos.size() >= 10) {
                ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13003");
                throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
            }
        }

        long s = System.currentTimeMillis();
        if (null != fieldsVo) {
            // 场地 vo 更改场地状态
            fieldsVo.setClaimStatus(2);
            fieldsVo.setUpdatedAt(now);

            // 场地 redis
            merchantRdmService.setFieldsVoByFieldId(fieldsVo.getFieldId(), fieldsVo);
            log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);
        }

        // 申请场地 vo
        MerchantFieldAppliesVo fieldsAppliesVo = MerchantFieldAppliesVo.getNew();
        BeanUtils.copyProperties(parameter, fieldsAppliesVo);
        fieldsAppliesVo.setFieldApplyId(IDGenerator.nextSnowId());
        fieldsAppliesVo.setApplyStatus(0);
        if (null != fieldsVo) {
            fieldsAppliesVo.setApplyType("claim");
        } else {
            fieldsAppliesVo.setApplyType("create");
        }
        fieldsAppliesVo.setReject("");
        fieldsAppliesVo.setUid(uid);
        fieldsAppliesVo.setCreatedAt(now);

        // 申请场地 redis
        s = System.currentTimeMillis();
        merchantRdmService.addFieldsAppliesVoByUid(uid, fieldsAppliesVos, fieldsAppliesVo);
        log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);

        if (null != fieldsVo) {
            // 场地 sql
            toMqSqls.add(SqlMapping.get("merchant_fields.update_claim_status"));
            fieldUpdateObjs.add(new Object[]{
                    fieldsVo.getClaimStatus(), fieldsVo.getUpdatedAt(), fieldsVo.getFieldId()
            });
        }
        // 申请场地 sql
        toMqSqls.add(SqlMapping.get("merchant_field_applies.insert"));
        fieldApplyInsertObjs.add(new Object[]{
                fieldsAppliesVo.getFieldApplyId(), fieldsAppliesVo.getApplyStatus(), fieldsAppliesVo.getApplyType(), fieldsAppliesVo.getReject(), fieldsAppliesVo.getUid(), fieldsAppliesVo.getFieldId(),
                fieldsAppliesVo.getName(), fieldsAppliesVo.getLogo(), fieldsAppliesVo.getBackground(), fieldsAppliesVo.getDescription(), fieldsAppliesVo.getBuiltDate(),
                fieldsAppliesVo.getProvinceId(), fieldsAppliesVo.getProvinceName(), fieldsAppliesVo.getCityId(), fieldsAppliesVo.getCityName(), fieldsAppliesVo.getDistrictId(), fieldsAppliesVo.getDistrictName(), fieldsAppliesVo.getAddress(), fieldsAppliesVo.getLongitude(), fieldsAppliesVo.getLatitude(),
                fieldsAppliesVo.getContactName(), fieldsAppliesVo.getContactEmail(), fieldsAppliesVo.getCompanyName(), fieldsAppliesVo.getLicenseCode(), fieldsAppliesVo.getLicenseImg(),
                fieldsAppliesVo.getLegalName(), fieldsAppliesVo.getLegalIdentity(), fieldsAppliesVo.getLegalIdentityObverse(), fieldsAppliesVo.getLegalIdentityReverse(), fieldsAppliesVo.getCreatedAt()
        });

        // mq
        s = System.currentTimeMillis();
        if (null != fieldsVo) {
            queueUtils.sendMsgByRedis(
                    MQConst.MerchantQueue.SQL_MERCHANT_FIELD.getKey(),
                    SqlMapping.gets(toMqSqls, fieldUpdateObjs, fieldApplyInsertObjs)
            );
        } else {
            queueUtils.sendMsgByRedis(
                    MQConst.MerchantQueue.SQL_MERCHANT_FIELD.getKey(),
                    SqlMapping.gets(toMqSqls, fieldApplyInsertObjs)
            );
        }
        log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);

        return fieldsAppliesVo.getFieldApplyId();
    }

    @Override
    public void editIsCheck(String uid, String fieldId, int isCheck) {
        LocalDateTime now = LocalDateTime.now();

        MerchantFieldsVo fieldsVo = merchantRdmService.getFieldsVoByFieldId(fieldId);

        if (null == fieldsVo || !fieldsVo.getUid().equals(uid)) {
            ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("13001");
            throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
        }

        // 场地 vo 更改是否自动审核
        fieldsVo.setIsCheck(isCheck > 0 ? 1 : 0);
        fieldsVo.setUpdatedAt(now);

        // 场地 redis
        long s = System.currentTimeMillis();
        merchantRdmService.setFieldsVoByFieldId(fieldsVo.getFieldId(), fieldsVo);
        log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);

        // 场地 mongo
        Query query = Query.query(Criteria.where("fieldId").is(fieldsVo.getFieldId()));
        Update update = Update.update("isCheck", fieldsVo.getIsCheck()).set("updateAt", fieldsVo.getUpdatedAt());
        mongoTemplate.updateFirst(query, update, MerchantFieldsVo.class, MerchantFieldsVo.class.getSimpleName());

        // 场地 sql
        LinkedList<String> toMqSqls = CollectionUtil.linkedListString();
        LinkedList<Object[]> fieldUpdateObjs = CollectionUtil.linkedListObjectArr();
        toMqSqls.add(SqlMapping.get("merchant_fields.update_is_check"));
        fieldUpdateObjs.add(new Object[]{
                fieldsVo.getIsCheck(), fieldsVo.getUpdatedAt(), fieldsVo.getFieldId()
        });

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