package com.liquidnet.service.adam.service.impl;

import com.github.pagehelper.PageInfo;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.adam.dto.vo.*;
import com.liquidnet.service.adam.entity.AdamDisposed;
import com.liquidnet.service.adam.mapper.AdamDisposedMapper;
import com.liquidnet.service.adam.service.IAdamDisposedService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.service.adam.service.IAdamUserService;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.feign.kylin.api.FeignKylinPerformanceClient;
import com.liquidnet.service.kylin.dto.vo.PerformanceVo;
import com.mongodb.BasicDBObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
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.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 想去 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2021-05-18
 */
@Slf4j
@Service
public class AdamDisposedServiceImpl extends ServiceImpl<AdamDisposedMapper, AdamDisposed> implements IAdamDisposedService {
    @Autowired
    MongoConverter mongoConverter;
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    IAdamUserService adamUserService;


    /* ---------------- 外部服务API ---------------- */
    @Autowired
    FeignKylinPerformanceClient kylinPerformanceClient;

    @Override
    public void add(AdamDisposedBaseVo disposedBaseVo) {
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.format(now, DateUtil.Formatter.yyyyMMddHHmmss);

        disposedBaseVo.setState(1);
        disposedBaseVo.setCreatedAt(nowStr);

        AdamUserInfoVo userInfoVo = adamUserService.queryByUid(disposedBaseVo.getUid());
        disposedBaseVo.setAvatar(userInfoVo.getAvatar());
        disposedBaseVo.setNickname(userInfoVo.getNickname());
        disposedBaseVo.setSex(userInfoVo.getSex());

        mongoTemplate.insert(disposedBaseVo, AdamDisposedBaseVo.class.getSimpleName());

        // TODO: 2021/5/19 sql to mq

    }

    @Override
    public AdamDisposedBaseVo query(String uid, String type, String contentId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("uid").is(uid).and("type").is(type)
                        .and("contentId").is(contentId).and("state").is(1)),
                AdamDisposedBaseVo.class, AdamDisposedBaseVo.class.getSimpleName());
    }

    @Override
    public void del(String uid, String type, String contentId) {
        AdamDisposedBaseVo delVo = AdamDisposedBaseVo.getNew();
        delVo.setState(2);
        delVo.setUpdatedAt(DateUtil.getNowTime());
        mongoTemplate.getCollection(AdamDisposedBaseVo.class.getSimpleName()).updateOne(
                Query.query(Criteria.where("uid").is(uid).and("type").is(type)
                        .and("contentId").is(contentId).and("state").is(1)).getQueryObject(),
                new BasicDBObject("$set", mongoConverter.convertToMongoType(delVo)));
    }

    @Override
    public boolean queryState(String uid, String type, String contentId) {
        long count = mongoTemplate.count(Query.query(Criteria.where("uid").is(uid).and("type").is(type)
                .and("contentId").is(contentId).and("state").is(1)), AdamDisposedBaseVo.class.getSimpleName());
        return count > 0;
    }

    @Override
    public PageInfo<AdamDisposedVo> queryPage(String uid, String type, int pageNo, int pageSize) {
        Query query = Query.query(Criteria.where("uid").is(uid).and("type").is(type).and("state").is(1));

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

        PageInfo<AdamDisposedVo> voPageInfo = null;
        if (count > 0) {
            query.with(PageRequest.of(pageNo - 1, pageSize, Sort.by(Sort.Direction.DESC, "createdAt")));

            List<AdamDisposedVo> disposedVoList = mongoTemplate.find(query, AdamDisposedVo.class, AdamDisposedBaseVo.class.getSimpleName());

            if (!CollectionUtils.isEmpty(disposedVoList)) {
                List<PerformanceVo> performanceVoList = null;
                try {
                    String[] contentIds = disposedVoList.stream().map(AdamDisposedVo::getContentId).toArray(a -> new String[disposedVoList.size()]);

                    ResponseDto<List<PerformanceVo>> performanceVoListDto = kylinPerformanceClient.performanceList(contentIds);

                    if (performanceVoListDto.isSuccess()) {
                        performanceVoList = performanceVoListDto.getData();
                    } else {
                        log.info("Failed:{}.API.performanceList(...) for AdamDisposedVo:{}", kylinPerformanceClient.getClass().getSimpleName(), performanceVoListDto.toJson());
                    }
                } catch (Exception e) {
                    log.error("Exception:{}.API.performanceList(...) for AdamDisposedVo >> {}", kylinPerformanceClient.getClass().getSimpleName(), e.getLocalizedMessage());
                }

                if (!CollectionUtils.isEmpty(performanceVoList)) {
                    performanceVoList.forEach(pv -> {
                        disposedVoList.forEach(v -> {
                            if (pv.getPerformancesId().equals(v.getContentId())) v.setContentInfo(pv);

                            PageInfo<AdamDisposedUserVo> disposedUserVoPageInfo = this.queryDisposedUsers(type, v.getContentId(), 1, 3);

                            if (disposedUserVoPageInfo.getTotal() > 0) v.setUserVos(disposedUserVoPageInfo.getList());
                        });
                    });
                } else {
                    disposedVoList.forEach(v -> {
                        PageInfo<AdamDisposedUserVo> disposedUserVoPageInfo = this.queryDisposedUsers(type, v.getContentId(), 1, 3);

                        if (disposedUserVoPageInfo.getTotal() > 0) v.setUserVos(disposedUserVoPageInfo.getList());
                    });
                }
            }

            voPageInfo = PageInfo.of(disposedVoList);
            voPageInfo.setTotal(count);
        } else {
            voPageInfo = new PageInfo<>();
        }

        return voPageInfo;
    }

    @Override
    public PageInfo<AdamDisposedUserVo> queryDisposedUsers(String type, String contentId, int pageNo, int pageSize) {
        Query query = Query.query(Criteria.where("type").is(type).and("contentId").is(contentId).and("state").is(1));

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

        PageInfo<AdamDisposedUserVo> voPageInfo = null;
        if (count > 0) {
            query.with(PageRequest.of(pageNo - 1, pageSize, Sort.by(Sort.Direction.DESC, "createdAt")));

            List<AdamDisposedUserVo> disposedUserVoList = mongoTemplate.find(query, AdamDisposedUserVo.class, AdamDisposedBaseVo.class.getSimpleName());

            voPageInfo = PageInfo.of(disposedUserVoList);
            voPageInfo.setTotal(count);
        } else {
            voPageInfo = new PageInfo<>();
        }
        return voPageInfo;
    }
}
