package cn.com.taiji.track.service.impl;

import cn.com.taiji.track.dto.IGeomesaTrackDTO;
import cn.com.taiji.track.entity.BeidouLocationEntity;
import cn.com.taiji.track.entity.BeidouTrackEntity;
import cn.com.taiji.track.mapper.BeidouTrackMapper;
import cn.com.taiji.track.service.IBeidouTrackService;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.filter.identity.FeatureIdImpl;
import org.geotools.util.factory.Hints;
import org.locationtech.geomesa.redis.data.RedisDataStore;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Description:
 * @Author: hujie@umisoft.cn
 * @Date: 2021/11/30 9:59 下午
 */
@Service
@Slf4j
public class BeidouTrackServiceImpl extends ServiceImpl<BeidouTrackMapper, BeidouTrackEntity> implements IBeidouTrackService {

    @Autowired
    protected StringRedisTemplate redisTemplate;
    @Autowired
    private SimpleFeatureType sft;
    @Autowired
    private RedisDataStore redisDataStore;
    @Autowired
    private IGeomesaTrackDTO geomesaTrackDTO;
    @Resource
    private KafkaTemplate kafkaTemplate;
    @Value("${taiji.kafka.productor.beidou.topic}")
    private String kafkaTopic;
    /**
     * 写入Redis
     * @param records
     */
    @Override
    public void beidouDynamicShipToRedis(List<ConsumerRecord<?, ?>> records){
        Date begain = null;
        try {
            begain = new Date();
            FeatureReader<SimpleFeatureType, SimpleFeature> reader = null;
            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = null;

            try {
                writer = redisDataStore.getFeatureWriterAppend(sft.getTypeName(), Transaction.AUTO_COMMIT);
                SimpleFeatureBuilder builder = new SimpleFeatureBuilder(sft);
                for (ConsumerRecord<?, ?> record : records) {
                    Optional message = Optional.ofNullable(record.value());
                    if (message.isPresent()) {
                        Object msg = message.get();
                        IGeomesaTrackDTO dto = JSONObject.parseObject(msg.toString(), geomesaTrackDTO.getClass());
                        dto.setKafkaConsumerGroup(geomesaTrackDTO.getKafkaConsumerGroup());
                        dto.setExpirySeconds(geomesaTrackDTO.getExpirySeconds());
                        if (!dto.checkPoint()) {
                            continue;
                        }
                        String fid = dto.getFid();
                        boolean append = true;
                        FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2();
                        Filter filter = null;
                        if(null != fid && !"".equals(fid)){
                            filter = filterFactory.id(filterFactory.featureId(fid));
                        }else {
                            String id = UUID.randomUUID().toString();
                            filter = filterFactory.id(filterFactory.featureId(id));
                        }
                        Query query = new Query(dto.getTypeName(), filter);
                        reader = redisDataStore.getFeatureReader(query, Transaction.AUTO_COMMIT);
                        if (reader.hasNext()) {
                            append = false;
                            String[] propList = dto.getPropList();
                            Object[] valueList = dto.getValueList();
                            redisDataStore.getFeatureSource(dto.getTypeName()).modifyFeatures(propList, valueList, filter);
                        }
                        reader.close();
                        reader = null;
                        if (append) {
                            SimpleFeature toWrite = writer.next();
                            builder.reset();
                            SimpleFeature feature = dto.toSimpleFeature(builder, fid);
                            toWrite.setAttributes(feature.getAttributes());
                            toWrite.getUserData().put(Hints.USE_PROVIDED_FID, Boolean.TRUE);
                            ((FeatureIdImpl) toWrite.getIdentifier()).setID(feature.getID());
                            toWrite.getUserData().putAll(feature.getUserData());
                            writer.write();
                        }
                    }
                }
            }  catch (Exception e) {
                log.error("=======发生异常============");
                e.printStackTrace();
            } finally {
                try {
                    if (null != writer) {
                        writer.close();
                    }
                    if (null != reader) {
                        reader.close();
                    }
                } catch (Exception e) {
                    log.error("=======close操作发生异常============");
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
//        log.info("轨迹数据写入图层完成！耗时 {} 毫秒, 从 消费组 {} 中合计消费 {} 条记录", (new Date()).getTime() - begain.getTime(), geomesaTrackDTO.getKafkaConsumerGroup(), records.size());
    }

    private  Vector<BeidouTrackEntity> trackEntities= new Vector<>();

    @Override
    public void beidouDynamicShipToCache(List<ConsumerRecord<?, ?>> records){
        try {
            for (ConsumerRecord<?, ?> record : records) {
                Optional message = Optional.ofNullable(record.value());
                if (message.isPresent()) {
                    Object msg = message.get();
                    BeidouTrackEntity entity = JSONObject.parseObject(msg.toString(), BeidouTrackEntity.class);
                    entity.setCreateTime(new Date());
                    entity.setUpdateTime(new Date());
                    trackEntities.add(entity);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void cacheBeidouToMySql() {
        Date begin = new Date();
        if(trackEntities.size() > 0){
            List<BeidouTrackEntity> saveList = new ArrayList<>(trackEntities);
            trackEntities.clear();
            saveBatch(saveList);
            log.info("轨迹数据写入数据库完成！耗时 {} 毫秒, 合计保存 {} 条记录", (new Date()).getTime() - begin.getTime(), saveList.size());
        }
    }

    /**
     * 写入Kafka
     * @param records
     */
    @Override
    public void beidouDynamicShipToKafka(List<ConsumerRecord<?, ?>> records) {
        Date begin = new Date();
        for (ConsumerRecord<?, ?> record : records) {
            Optional message = Optional.ofNullable(record.value());
            Object msg = message.get();
            BeidouTrackEntity entity = JSONObject.parseObject(msg.toString(), BeidouTrackEntity.class);
            String data = JSONUtil.toJsonStr(entity);
            kafkaTemplate.send(kafkaTopic, entity.getDeviceId(),data);
        }
//        log.info("轨迹数据转发kafka完成！耗时 {} 毫秒, 合计转发 {} 条记录", (new Date()).getTime() - begin.getTime(), records.size());
    }
}
