package com.gyee.wisdom.dao.golden;

import com.golden.api.impl.GoldenServerImpl;
import com.gyee.wisdom.common.data.timeseries.*;
import com.gyee.wisdom.common.exception.WisdomException;
import com.gyee.wisdom.dao.timeseries.GoldenDao;
import com.gyee.wisdom.dao.timeseries.ILatestDao;
import com.rtdb.api.callbackInter.RSDataChangeEx;
import com.rtdb.api.model.RtdbData;
import com.rtdb.enums.Quality;
import com.rtdb.model.*;
import com.rtdb.service.impl.BaseImpl;
import com.rtdb.service.impl.ServerImpl;
import com.rtdb.service.impl.SnapshotImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

@Component
@GoldenDao
public class GoldenLatestDao implements ILatestDao {

    @Autowired
    private GoldenConfig goldenConfig;


    public Map<String, TsData> getTsDataLatest(List<TsPoint> tsPoints) throws Exception {
        Map<String, TsData> result = new HashMap<>();
        Map<TsDataType, List<TsPoint>> pointGroup = tsPoints.stream().collect(Collectors.groupingBy(TsPoint::getTsDataType));
        for (Map.Entry<TsDataType, List<TsPoint>> entry : pointGroup.entrySet()) {
            String[] tagNames = entry.getValue().stream().map(TsPoint::getId).toArray(String[]::new);
            if (entry.getKey() == TsDataType.DOUBLE) {
                result.putAll(getDoubleTsDataSnapshots(tagNames));
            } else if (entry.getKey() == TsDataType.LONG) {
                result.putAll(getLongTsDataSnapshots(tagNames));
            } else if (entry.getKey() == TsDataType.BOOLEAN) {
                result.putAll(getBooleanTsDataSnapshots(tagNames));
            } else if (entry.getKey() == TsDataType.COORDINATE) {
                result.putAll(getCoordinateTsDataSnapshots(tagNames));
            } else {
                throw new WisdomException("Golden不支持数据类型:" + entry.getKey());
            }
        }

       // RtdbData tmp = new RtdbData();

        return result;
    }

    public Map<String, TsData> getDoubleTsDataSnapshots(String... tagNames) throws Exception {
        ServerImpl connection = null;
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            List<MinPoint> lstPoint = base.findPoints(tagNames);
            int[] ids = lstPoint.stream().mapToInt(MinPoint::getId).toArray();
            Entity<DoubleData> entityD = snap.getDoubleSnapshots(ids);
            //DoubleData[] arr = new DoubleData[entityD.getSucCount()];
            //entityD.getList().toArray(arr);
            Map<String, TsData> tsDataMap = new HashMap<>();
            for (int i = 0; i < tagNames.length; i++) {
                tsDataMap.put(tagNames[i],
                        new DoubleTsData(entityD.getList().get(i).getDateTime().getTime(),
                                entityD.getList().get(i).getQuality(),
                                entityD.getList().get(i).getValue()));
            }
            //throw new Exception("");
            return tsDataMap;
        } finally {
            if (connection != null)
                this.goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    public Map<String, TsData> getLongTsDataSnapshots(String... tagNames) throws Exception {
        ServerImpl connection = null;
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            List<MinPoint> lstPoint = base.findPoints(tagNames);
            int[] ids = lstPoint.stream().mapToInt(MinPoint::getId).toArray();
            Entity<IntData> entityD = snap.getIntSnapshots(ids);
            Map<String, TsData> tsDataMap = new HashMap<>();
            for (int i = 0; i < tagNames.length; i++) {
                tsDataMap.put(tagNames[i],
                        new LongTsData(entityD.getList().get(i).getDateTime().getTime(),
                                entityD.getList().get(i).getQuality(),
                                (long) entityD.getList().get(i).getValue()));
            }
            return tsDataMap;
        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    public Map<String, TsData> getBooleanTsDataSnapshots(String... tagNames) throws Exception {
        ServerImpl connection = null;
        try {
            connection = this.goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl  base = new BaseImpl(connection);
            List<MinPoint> lstPoint = base.findPoints(tagNames);
            int[] ids = lstPoint.stream().mapToInt(MinPoint::getId).toArray();
            Entity<IntData> entityD = snap.getIntSnapshots(ids);
            Map<String, TsData> tsDataMap = new HashMap<>();
            for (int i = 0; i < tagNames.length; i++) {
                tsDataMap.put(tagNames[i],
                        new BooleanTsData(entityD.getList().get(i).getDateTime().getTime(),
                                entityD.getList().get(i).getQuality(),
                                entityD.getList().get(i).getValue() != 0));
            }
            return tsDataMap;
        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    public Map<String, TsData> getCoordinateTsDataSnapshots(String... tagNames) throws Exception {
        ServerImpl connection = null;        
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            List<MinPoint> lstPoint = base.findPoints(tagNames);
            int[] ids = lstPoint.stream().mapToInt(MinPoint::getId).toArray();
            Entity<CoorData> entityD = snap.getCoorSnapshots(ids);
            Map<String, TsData> tsDataMap = new HashMap<>();
            for (int i = 0; i < tagNames.length; i++) {
                tsDataMap.put(tagNames[i],
                        new CoordinateTsData(entityD.getList().get(i).getDateTime().getTime(),
                                entityD.getList().get(i).getQuality(),
                                entityD.getList().get(i).getY(),
                                entityD.getList().get(i).getX()));
            }
            return tsDataMap;
        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    public int writeDoubleLatest(List<TsPointData> list) throws Exception {
        ServerImpl connection = null;
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            String[] tagNames = list.stream().map(TsPointData::getTagName).toArray(String[]::new);
            List<MinPoint> pointList = base.findPoints(tagNames);
            List<DoubleData> doubleList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                Date time = new Date();
                time.setTime(list.get(0).getTsData().getTs());
                DoubleData data = new DoubleData(pointList.get(i).getId(), time, list.get(i).getTsData().getDoubleValue().get()
                        , (short) 0, 0);
                doubleList.add(data);
            }
            int count = snap.putDoubleSnapshots(doubleList);
            return count;
        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    @Override
    public int writeStringLatest(List<TsPointData> list) throws Exception {
        ServerImpl connection = null;
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            String[] tagNames = list.stream().map(TsPointData::getTagName).toArray(String[]::new);
            List<MinPoint> pointList = base.findPoints(tagNames);
            List<BlobData> blobList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                BlobData pointData = new BlobData();
                Date date = new Date();
                date.setTime(list.get(i).getTsData().getTs());
                pointData.setDatetime((date));
                pointData.setId(pointList.get(i).getId());
                pointData.setQuality(Quality.GOOD);
                pointData.setBlob(list.get(i).getTsData().getBlobValue().get().getBytes());
                blobList.add(pointData);
            }
            int count = snap.putBlobSnapshots(blobList);
            return count;
        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }

    }

    @Override
    public int writeBooleanLatest(List<TsPointData> list) throws Exception {
        ServerImpl connection = null;
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            String[] tagNames = list.stream().map(TsPointData::getTagName).toArray(String[]::new);
            List<MinPoint> pointList = base.findPoints(tagNames);
            List<IntData> intList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {
                IntData pointData = new IntData();
                Date date = new Date();
                date.setTime(list.get(i).getTsData().getTs());
                pointData.setDateTime(date);
                pointData.setId(pointList.get(i).getId());
                pointData.setQuality((short) 0);
                pointData.setValue(list.get(i).getTsData().getBooleanValue().get() ? 1 : 0);
                intList.add(pointData);
            }
            int count = snap.putIntSnapshots(intList);
            return count;
        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    @Override
    public int writeLongLatest(List<TsPointData> list) throws Exception {
      
        ServerImpl connection = null;
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            String[] tagNames = list.stream().map(TsPointData::getTagName).toArray(String[]::new);
            List<MinPoint> pointList = base.findPoints(tagNames);
            List<DatetimeData> datetimeList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {

                DatetimeData pointData = new DatetimeData();
                Date date = new Date();
                date.setTime(list.get(i).getTsData().getTs());
                pointData.setDateTime(date);
                pointData.setId(pointList.get(i).getId());
                pointData.setQuality((short) 0);
                date.setTime(list.get(i).getTsData().getLongValue().get());
                pointData.setValue(date);
                datetimeList.add(pointData);
            }
            int count = snap.putDatetimeSnapshots(datetimeList).getSucCount();
            return count;
        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    @Override
    public int writeBlobLatest(List<TsPointData> list) throws Exception {
        ServerImpl connection = null;
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            String[] tagNames = list.stream().map(TsPointData::getTagName).toArray(String[]::new);
            List<MinPoint> pointList = base.findPoints(tagNames);
            List<BlobData> dataList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {

                BlobData pointData = new BlobData();
                Date date = new Date();
                date.setTime(list.get(i).getTsData().getTs());
                pointData.setDatetime((date));
                pointData.setId(pointList.get(i).getId());
                pointData.setQuality(Quality.GOOD);
                pointData.setBlob(list.get(i).getTsData().getBlobValue().get().getBytes());
                pointData.setLen(list.get(i).getTsData().getBlobValue().get().getBytes().length);
                dataList.add(pointData);
            }
            int count = snap.putBlobSnapshots(dataList);
            return count;

        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    @Override
    public int writeCoordinateLatest(List<TsPointData> list) throws Exception {
        ServerImpl connection = null;
        try {
            connection = goldenConfig.getGoldenConnectionPool().getConnection();
            SnapshotImpl snap = new SnapshotImpl(connection);
            BaseImpl base = new BaseImpl(connection);
            String[] tagNames = list.stream().map(TsPointData::getTagName).toArray(String[]::new);
            List<MinPoint> pointList = base.findPoints(tagNames);
            List<CoorData> dataList = new ArrayList<>();
            for (int i = 0; i < list.size(); i++) {

                CoorData pointData = new CoorData();
                Date date = new Date();
                date.setTime(list.get(i).getTsData().getTs());
                pointData.setDateTime((date));
                pointData.setId(pointList.get(i).getId());
                pointData.setQuality((short) 0);
                pointData.setX((float) list.get(i).getTsData().getCoordinateValue().get().getLongitude());
                pointData.setY((float) list.get(i).getTsData().getCoordinateValue().get().getLatitude());
                dataList.add(pointData);
            }
            int count = snap.putCoorSnapshots(dataList);
            return count;

        } finally {
            if (connection != null)
                goldenConfig.getGoldenConnectionPool().returnConnection(connection);
        }
    }

    @Override
    public boolean writeLatest(List<TsPointData> dataList) throws Exception {
        int writeCount = 0;

        Map<TsDataType, List<TsPointData>> pointGroup = dataList.stream().collect(Collectors.groupingBy(TsPointData::findDataType));
        for (Map.Entry<TsDataType, List<TsPointData>> entry : pointGroup.entrySet()) {
            List<TsPointData> pointDataList = entry.getValue();
            if (entry.getKey() == TsDataType.DOUBLE) {
                int count = writeDoubleLatest(pointDataList);
                writeCount = writeCount + count;
            } else if (entry.getKey() == TsDataType.BOOLEAN) {
                int count = writeBooleanLatest(pointDataList);
                writeCount = writeCount + count;
            } else if (entry.getKey() == TsDataType.STRING) {
                int count = writeStringLatest(pointDataList);
                writeCount = writeCount + count;
            } else if (entry.getKey() == TsDataType.BLOB) {
                int count = writeBlobLatest(pointDataList);
                writeCount = writeCount + count;
            } else if (entry.getKey() == TsDataType.COORDINATE) {
                int count = writeCoordinateLatest(pointDataList);
                writeCount = writeCount + count;
            } else if (entry.getKey() == TsDataType.LONG) {
                int count = writeLongLatest(pointDataList);
                writeCount = writeCount + count;
            }
        }
        return writeCount > 0 ? true : false;

    }



}
