package cz.senslog.connector.model.converter;

import cz.senslog.connector.model.api.Converter;
import cz.senslog.connector.model.soilscount.Measurement;
import cz.senslog.connector.model.soilscount.SoilscountModel;
import cz.senslog.connector.model.v1.Observation;
import cz.senslog.connector.model.v1.Record;
import cz.senslog.connector.model.v1.SenslogV1Model;

import java.time.OffsetDateTime;
import java.util.*;
import java.util.function.Function;

public class SoilscountSenslogV1Converter implements Converter<SoilscountModel, SenslogV1Model> {

    private static final Map<Long, Function<Measurement, List<Observation>>> DEVICE_TO_UNIT_ID;

    private static final int NM_OF_SENSORS;

    static {
        NM_OF_SENSORS = 3;
        DEVICE_TO_UNIT_ID = new HashMap<>();
        DEVICE_TO_UNIT_ID.put(28779L, (u) -> Arrays.asList(
                new Observation(){{setUnitId(428024647L); setSensorId(410240030L); setValue(u.getMoisture());      }},
                new Observation(){{setUnitId(428024647L); setSensorId(340620030L); setValue(u.getTemperature());   }},
                new Observation(){{setUnitId(428024647L); setSensorId(580040030L); setValue(u.getOxygen());        }}
        ));

        DEVICE_TO_UNIT_ID.put(28780L, (u) -> Arrays.asList(
                new Observation(){{setUnitId(428024656L); setSensorId(410240015L); setValue(u.getMoisture());      }},
                new Observation(){{setUnitId(428024656L); setSensorId(340620015L); setValue(u.getTemperature());   }},
                new Observation(){{setUnitId(428024656L); setSensorId(580040015L); setValue(u.getOxygen());        }}
        ));

        DEVICE_TO_UNIT_ID.put(28781L, (u) -> Arrays.asList(
                new Observation(){{setUnitId(428024699L); setSensorId(410240030L); setValue(u.getMoisture());      }},
                new Observation(){{setUnitId(428024699L); setSensorId(340620030L); setValue(u.getTemperature());   }},
                new Observation(){{setUnitId(428024699L); setSensorId(570060030L); setValue(u.getSalinity());        }}
        ));

        DEVICE_TO_UNIT_ID.put(28782L, (u) -> Arrays.asList(
                new Observation(){{setUnitId(428024700L); setSensorId(410240015L); setValue(u.getMoisture());      }},
                new Observation(){{setUnitId(428024700L); setSensorId(340620015L); setValue(u.getTemperature());   }},
                new Observation(){{setUnitId(428024700L); setSensorId(570060015L); setValue(u.getSalinity());      }}
        ));

        DEVICE_TO_UNIT_ID.put(28783L, (u) -> Arrays.asList(
                new Observation(){{setUnitId(428024701L); setSensorId(410240030L); setValue(u.getMoisture());      }},
                new Observation(){{setUnitId(428024701L); setSensorId(340620030L); setValue(u.getTemperature());   }},
                new Observation(){{setUnitId(428024701L); setSensorId(570060030L); setValue(u.getSalinity());      }}
        ));

        DEVICE_TO_UNIT_ID.put(28784L, (u) -> Arrays.asList(
                new Observation(){{setUnitId(428024702L); setSensorId(410240015L); setValue(u.getMoisture());      }},
                new Observation(){{setUnitId(428024702L); setSensorId(340620015L); setValue(u.getTemperature());   }},
                new Observation(){{setUnitId(428024702L); setSensorId(570060015L); setValue(u.getSalinity());      }}
        ));

        DEVICE_TO_UNIT_ID.put(28785L, (u) -> Arrays.asList(
                new Observation(){{setUnitId(428024703L); setSensorId(410240030L); setValue(u.getMoisture());      }},
                new Observation(){{setUnitId(428024703L); setSensorId(340620030L); setValue(u.getTemperature());   }},
                new Observation(){{setUnitId(428024703L); setSensorId(570060030L); setValue(u.getSalinity());      }}
        ));

        DEVICE_TO_UNIT_ID.put(28786L, (u) -> Arrays.asList(
                new Observation(){{setUnitId(428024704L); setSensorId(410240015L); setValue(u.getMoisture());       }},
                new Observation(){{setUnitId(428024704L); setSensorId(340620015L); setValue(u.getTemperature());    }},
                new Observation(){{setUnitId(428024704L); setSensorId(570060015L); setValue(u.getSalinity());       }}
        ));
    }

    @Override
    public SenslogV1Model convert(SoilscountModel inputModel) {
        if (inputModel == null) { return null; }
        if (inputModel.getMeasurement() == null || inputModel.getMeasurement().isEmpty()) {
            return new SenslogV1Model(Collections.emptyList(), inputModel.getFrom(), inputModel.getTo());
        }

        List<Record> observations = new ArrayList<>(inputModel.getMeasurement().size() * NM_OF_SENSORS);
        for (Measurement measurement : inputModel.getMeasurement()) {
            if (!DEVICE_TO_UNIT_ID.containsKey(measurement.getDeviceId())) { continue; }

            OffsetDateTime timestamp = measurement.getTimestamp();
            for (Observation observation : DEVICE_TO_UNIT_ID.get(measurement.getDeviceId()).apply(measurement)) {
                if (observation.getValue() != null) {
                    observation.setTime(timestamp);
                    observations.add(observation);
                }
            }
        }

        return new SenslogV1Model(observations, inputModel.getFrom(), inputModel.getTo());
    }
}
