// Copyright (c) 2020 UWB & LESP.
// The UWB & LESP license this file to you under the MIT license.

package cz.senslog.connector.model.converter;

import cz.senslog.connector.model.api.Converter;
import cz.senslog.connector.model.azure.AzureModel;
import cz.senslog.connector.model.azure.SensorData;
import cz.senslog.connector.model.azure.SensorInfo;
import cz.senslog.connector.model.v1.Observation;
import cz.senslog.connector.model.v1.Record;
import cz.senslog.connector.model.v1.SenslogV1Model;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static cz.senslog.connector.model.converter.AzureUnitConverter.convertEuiToUnitId;
import static cz.senslog.connector.model.converter.AzureUnitConverter.convertSensorTypeToSensorId;
import static java.util.Collections.emptyList;

/**
 * The class {@code AzureModelSenslogV1ModelConverter} represents an implementation of converter
 * between {@link AzureModel} and {@link SenslogV1Model}.
 *
 * Converter converts input model of sensors data to observations. Each physical quantity of sensor
 * is converted as a single observation.
 *
 * @author Lukas Cerny
 * @version 1.0
 * @since 1.0
 */
public final class AzureModelSenslogV1ModelConverter implements Converter<AzureModel, SenslogV1Model> {

    private static final Logger logger = LogManager.getLogger(AzureModelSenslogV1ModelConverter.class);

    @Override
    public SenslogV1Model convert(AzureModel inputModel) {

        if (inputModel == null || inputModel.getSensors() == null) {
            logger.warn("Nothing to convert. Received model is empty.");
            return null;
        }

        List<SensorInfo> sensorInfos = inputModel.getSensors();

        int records = 0;
        for (SensorInfo sensorInfo : sensorInfos) {
            records += sensorInfo.getData() != null ? sensorInfo.getData().size() : 0;
        }
        logger.info("Received {} sensors and {} records to convert.", sensorInfos.size(), records);

        logger.debug("Creating an empty list of observation.");
        List<Record> observations = new ArrayList<>();

        for (SensorInfo sensorInfo : sensorInfos) {
            logger.debug("Converting sensor with Eui {}.", sensorInfo.getEui());

            Long unitId = convertEuiToUnitId(sensorInfo.getEui());
            if (unitId == null) {
                logger.error("EUI converter for '{}' does not exist.", sensorInfo.getEui()); continue;
            }

            List<SensorData> dataOfSensor = sensorInfo.getData() != null ? sensorInfo.getData() : emptyList();
            for (SensorData sensorData : dataOfSensor) {
                for (Map.Entry<String, Float> sensorDataEntry : sensorData.getValues().entrySet()) {
                    String sensorType = sensorDataEntry.getKey();
                    Long sensorId = convertSensorTypeToSensorId(sensorInfo.getEui(), sensorType);
                    if (sensorId == null) {
                        logger.error("Converter for the sensor type '{}' does not exist.", sensorType); continue;
                    }

                    logger.debug("Creating a new observation.");
                    Observation observation = new Observation();
                    observation.setSensorId(sensorId);
                    observation.setUnitId(unitId);
                    observation.setTime(sensorData.getTime());
                    observation.setValue(sensorDataEntry.getValue());

                    logger.debug("Saving the new observation.");
                    observations.add(observation);
                }
            }
        }

        logger.debug("Creating a new SenslogV1 model.");
        SenslogV1Model outputModel = new SenslogV1Model(observations, inputModel.getFrom(), inputModel.getTo());
        logger.debug("Conversion was completed successfully.");
        return outputModel;
    }
}
