package com.liquidnet.service.adam.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.adam.dto.AdamAddressesParam;
import com.liquidnet.service.adam.dto.vo.AdamAddressesVo;
import com.liquidnet.service.adam.service.AdamRdmService;
import com.liquidnet.service.adam.service.IAdamAddressesService;
import com.liquidnet.service.adam.util.QueueUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
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;

/**
 * <p>
 * 收货地址 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2021-05-11
 */
@Slf4j
@Service
public class AdamAddressesServiceImpl implements IAdamAddressesService {
//    @Autowired
//    MongoTemplate mongoTemplate;
    @Autowired
    QueueUtils queueUtils;
    @Autowired
    AdamRdmService adamRdmService;

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String add(AdamAddressesParam parameter) {
        LocalDateTime now = LocalDateTime.now();
        String currentUid = CurrentUtil.getCurrentUid();

        List<AdamAddressesVo> vos = adamRdmService.getAddressesVoByUid(currentUid);

        AdamAddressesVo vo = AdamAddressesVo.getNew();
        BeanUtils.copyProperties(parameter, vo);
        vo.setAddressesId(IDGenerator.nextSnowId());
        vo.setUid(currentUid);
        vo.setIsDefault(CollectionUtils.isEmpty(vos));
        vo.setState(1);
        vo.setCreatedAt(now);

//        long s = System.currentTimeMillis();
//        mongoTemplate.insert(vo, AdamAddressesVo.class.getSimpleName());
//        log.debug("#MDB耗时:{}ms", System.currentTimeMillis() - s);

        long s = System.currentTimeMillis();
//        adamRdmService.delAddressesVoByUid(currentUid);
        adamRdmService.addAddressesVoByUid(currentUid, vos, vo);
        log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);

        s = System.currentTimeMillis();
        queueUtils.sendMsgByRedis(
                MQConst.AdamQueue.SQL_UCENTER.getKey(),
                SqlMapping.get("adam_addresses.add",
                        vo.getAddressesId(), vo.getUid(), vo.getName(), vo.getPhone(), vo.getProvince(), vo.getCity(), vo.getCounty(), vo.getAddress(), vo.getIsDefault(), vo.getState(), now
                )
        );
        log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);
        return vo.getAddressesId();
    }

    @Override
    public void def(String uid, String addressesId) {
        LocalDateTime now = LocalDateTime.now();

        LinkedList<Object[]> toMqObjs = CollectionUtil.linkedListObjectArr();
        List<AdamAddressesVo> vos = adamRdmService.getAddressesVoByUid(uid);
        if (vos.size() > 1) {// 取消原默认
//            AdamAddressesVo unDeaultVo = AdamAddressesVo.getNew();
//            unDeaultVo.setIsDefault(false);
//            unDeaultVo.setUpdatedAt(now);
//            long s = System.currentTimeMillis();
//            Document doc = mongoTemplate.getCollection(AdamAddressesVo.class.getSimpleName()).findOneAndUpdate(
//                    Query.query(Criteria.where("uid").is(uid).and("state").is(1).and("isDefault").is(true)).getQueryObject(),
//                    new Document("$set", new Document("isDefault", false).append("updatedAt", now)),
//                    new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
//            );
//            log.debug("#MDB耗时:{}ms", System.currentTimeMillis() - s);
//            if (null != doc) {
//                AdamAddressesVo unDefaultVoAfter = BsonUtil.toBean(doc, AdamAddressesVo.class);
                AdamAddressesVo defaultVo = queryDefault(vos, uid, false);
                defaultVo.setIsDefault(false);
                defaultVo.setUpdatedAt(now);

                toMqObjs.add(new Object[]{false, now, defaultVo.getAddressesId()});

                this.collectionProcess(vos, defaultVo.getAddressesId(), defaultVo);
//            }
        }
        {// 设置新默认
//            AdamAddressesVo defaultVo = AdamAddressesVo.getNew();
//            defaultVo.setIsDefault(true);
//            defaultVo.setUpdatedAt(now);
//            long s = System.currentTimeMillis();
//            Document doc = mongoTemplate.getCollection(AdamAddressesVo.class.getSimpleName()).findOneAndUpdate(
//                    Query.query(Criteria.where("uid").is(uid).and("addressesId").is(addressesId)).getQueryObject(),
//                    new Document("$set", new Document("isDefault", true).append("updatedAt", now)),
//                    new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
//            );
//            log.debug("#MDB耗时:{}ms", System.currentTimeMillis() - s);
//            if (null != doc) {
//                AdamAddressesVo defaultVoAfter = BsonUtil.toBean(doc, AdamAddressesVo.class);
                AdamAddressesVo defaultVoAfter = adamRdmService.getAddressesVoByUidAddressesId(vos, addressesId);
                defaultVoAfter.setIsDefault(true);
                defaultVoAfter.setUpdatedAt(now);

                toMqObjs.add(new Object[]{true, now, addressesId});

                this.collectionProcess(vos, defaultVoAfter.getAddressesId(), defaultVoAfter);
//            }
        }
        if (!CollectionUtils.isEmpty(toMqObjs)) {
            long s = System.currentTimeMillis();
            adamRdmService.setAddressesVoByUid(uid, vos);
            log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);
            s = System.currentTimeMillis();
            queueUtils.sendMsgByRedis(
                    MQConst.AdamQueue.SQL_UCENTER.getKey(),
                    SqlMapping.get("adam_addresses.update.is_default", toMqObjs)
            );
            log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);
        }
    }

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void edit(AdamAddressesParam parameter) {
        String currentUid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();

        List<AdamAddressesVo> vos = adamRdmService.getAddressesVoByUid(currentUid);
        AdamAddressesVo updateVo = adamRdmService.getAddressesVoByUidAddressesId(vos, parameter.getAddressesId());
        updateVo.setName(parameter.getName());
        updateVo.setPhone(parameter.getPhone());
        updateVo.setProvince(parameter.getProvince());
        updateVo.setCity(parameter.getCity());
        updateVo.setCounty(parameter.getCounty());
        updateVo.setAddress(parameter.getAddress());
        updateVo.setUpdatedAt(now);
//        AdamAddressesVo updateVo = AdamAddressesVo.getNew();
//        BeanUtils.copyProperties(parameter, updateVo);
//        long s = System.currentTimeMillis();
//        Document doc = mongoTemplate.getCollection(AdamAddressesVo.class.getSimpleName()).findOneAndUpdate(
//                Query.query(Criteria.where("uid").is(currentUid).and("addressesId").is(parameter.getAddressesId())).getQueryObject(),
//                new Document("$set", Document.parse(JsonUtils.toJson(updateVo)).append("updatedAt", now)),
//                new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
//        );
//        log.debug("#MDB耗时:{}ms", System.currentTimeMillis() - s);
//        if (null != doc) {
//            updateVo = BsonUtil.toBean(doc, AdamAddressesVo.class);
//
//            List<AdamAddressesVo> vos = adamRdmService.getAddressesVoByUid(currentUid);
            long s = System.currentTimeMillis();
            adamRdmService.setAddressesVoByUid(updateVo.getUid(), this.collectionProcess(vos, parameter.getAddressesId(), updateVo));
            log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);

            s = System.currentTimeMillis();
            queueUtils.sendMsgByRedis(
                    MQConst.AdamQueue.SQL_UCENTER.getKey(),
                    SqlMapping.get("adam_addresses.edit",
                            updateVo.getName(), updateVo.getPhone(), updateVo.getProvince(), updateVo.getCity(), updateVo.getCounty(), updateVo.getAddress(), now, updateVo.getAddressesId()
                    )
            );
            log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);
//        }
    }

    @Override
//    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void remove(String uid, String addressesId) {
//        String currentUid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();

//        AdamAddressesVo removeVo = AdamAddressesVo.getNew();
//        removeVo.setState(2);
//        removeVo.setIsDefault(false);
//        removeVo.setUpdatedAt(now);
//        removeVo.setDeletedAt(now);

//        long s = System.currentTimeMillis();
//        DeleteResult deleteResult = mongoTemplate.remove(
//                Query.query(Criteria.where("uid").is(currentUid).and("addressesId").is(addressesId)), AdamAddressesVo.class.getSimpleName()
//        );
//        log.debug("#MDB耗时:{}ms", System.currentTimeMillis() - s);
//        List<AdamAddressesVo> vos = adamRdmService.getAddressesVoByUid(uid);
//        vos.removeIf(r -> r.getAddressesId().equals(addressesId));
//        s = System.currentTimeMillis();
//        adamRdmService.setAddressesVoByUid(uid, vos);
//        log.debug("#RDS耗时:{}ms", System.currentTimeMillis() - s);
        adamRdmService.rmvAddressesVoByUid(uid, adamRdmService.getAddressesVoByUid(uid), addressesId);

        long s = System.currentTimeMillis();
        queueUtils.sendMsgByRedis(
                MQConst.AdamQueue.SQL_UCENTER.getKey(),
                SqlMapping.get("adam_addresses.remove", now, now, addressesId)
        );
        log.debug("#MQ耗时:{}ms", System.currentTimeMillis() - s);
    }

    @Override
    public AdamAddressesVo queryDefault(List<AdamAddressesVo> vos, String uid, boolean downgrade) {
        if (CollectionUtils.isEmpty(vos)) {
            vos = adamRdmService.getAddressesVoByUid(uid);
        }
        if (!CollectionUtils.isEmpty(vos)) {
            AdamAddressesVo defaultVo = null;
            for (AdamAddressesVo vo : vos) {
                if (vo.getIsDefault()) {
                    return vo;
                }
                if (downgrade) {
                    defaultVo = null == defaultVo ? vo :
                            vo.getCreatedAt().compareTo(defaultVo.getCreatedAt()) > 0 ? vo : defaultVo;
                }
            }
            return defaultVo;
        }
        return null;
    }

    /* ---------------------------------------------------------------  */

    private List<AdamAddressesVo> collectionProcess(List<AdamAddressesVo> vos, String replaceId, AdamAddressesVo updateVo) {
        long s = System.currentTimeMillis();
        int idx = IntStream.range(0, vos.size())
                .filter(i -> vos.get(i).getAddressesId().equals(replaceId))
                .findFirst().orElse(-1);
        if (idx == -1) {
//            adamRdmService.delAddressesVoByUid(updateVo.getUid());
//
//            List<AdamAddressesVo> addressesVos = adamRdmService.getAddressesVoByUid(updateVo.getUid());
//
//            idx = IntStream.range(0, vos.size())
//                    .filter(i -> addressesVos.get(i).getAddressesId().equals(replaceId))
//                    .findFirst().orElse(-1);
//
//            if (idx == -1) {
                ErrorMapping.ErrorMessage errorMessage = ErrorMapping.get("10018");
                throw new LiquidnetServiceException(errorMessage.getCode(), errorMessage.getMessage());
//            }
        }
        vos.set(idx, updateVo);
        log.debug("#collect.process耗时:{}ms", System.currentTimeMillis() - s);
        return vos;
    }
}
