package cz.senslog.connector.fetch.fieldclimate;

import com.google.gson.reflect.TypeToken;
import cz.senslog.connector.fetch.api.ConnectorFetcher;
import cz.senslog.connector.fetch.api.FetchProxySession;
import cz.senslog.connector.model.config.HostConfig;
import cz.senslog.connector.tools.http.HttpClient;
import cz.senslog.connector.tools.http.HttpRequest;
import cz.senslog.connector.tools.http.HttpResponse;
import cz.senslog.connector.tools.http.URLBuilder;
import cz.senslog.connector.model.fieldclimate.FieldClimateModel;
import cz.senslog.connector.tools.util.Tuple;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Type;
import java.time.OffsetDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

import static cz.senslog.connector.fetch.fieldclimate.FieldClimateSession.emptySession;
import static cz.senslog.connector.tools.json.BasicJson.jsonToObject;
import static cz.senslog.connector.model.converter.FieldClimateUnitConverter.convertIdToFieldClimateId;
import static java.time.OffsetDateTime.parse;
import static java.time.format.DateTimeFormatter.ofPattern;

public class FieldClimateProxySession extends FetchProxySession<FieldClimateSession, FieldClimateModel> {

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

    protected static class ObservationInfo { OffsetDateTime timeStamp; Long unitId; }

    private final HttpClient httpClient;
    private final FieldClimateSessionProxyConfig config;

    public FieldClimateProxySession(
            ConnectorFetcher<FieldClimateSession, FieldClimateModel> instance,
            FieldClimateSessionProxyConfig config,
            HttpClient httpClient
    ) {
        super(instance);
        this.config = config;
        this.httpClient = httpClient;
    }

    @Override
    protected FieldClimateSession preProcessing(Optional<FieldClimateSession> previousSession) {

        HostConfig host = config.getLastObservationHost();
        logger.info("Getting last observations from {}.", host.getDomain());

        HttpRequest request = HttpRequest.newBuilder().GET()
                .url(URLBuilder.newBuilder(host.getDomain(), host.getPath())
                        .addParam("Operation", "GetLastObservations")
                        .addParam("group", config.getGroup())
                        .addParam("user", config.getUser())
                        .build())
                .build();
        logger.info("Creating a http request to {}.", request);

        HttpResponse response = httpClient.send(request);
        logger.info("Received a response with a status: {} for the domain {}.", response.getStatus(), host.getDomain());

        if (response.isError()) {
            logger.error("Can not get data from the server {}. Error {} {}",
                    host.getDomain(), response.getStatus(), response.getBody());
            return emptySession();
        }

        logger.debug("Parsing body of the response to the list of class {}.", ObservationInfo.class);
        Type lastObsType = new TypeToken<Collection<ObservationInfo>>() {}.getType();
        List<ObservationInfo> lastObservations = jsonToObject(response.getBody(), lastObsType,
                Tuple.of(OffsetDateTime.class, el -> parse(el, ofPattern("yyyy-MM-dd HH:mm:ssX")))
        );

        FieldClimateSession session = previousSession.filter(FieldClimateSession::isActive)
                .orElse(new FieldClimateSession(true));
        logger.debug("Created a new session of {}.", FieldClimateSession.class);

        logger.debug("Filling the new session of last timestamps from observations per each station.");
        for (ObservationInfo info : lastObservations) {
            String fcUnitId = convertIdToFieldClimateId(info.unitId);
            session.addLastUnitTime(fcUnitId, info.timeStamp);
        }

        logger.info("Loaded and successfully parsed {} last observations from stations.", lastObservations.size());
        return session;
    }

    @Override
    protected void postProcessing(Optional<FieldClimateModel> returnedModel, Optional<FieldClimateSession> currentSession) {
        if (currentSession.isPresent() && currentSession.get().isActive()) {
            FieldClimateSession session = currentSession.get();
            // TODO persistence the current session
        }
    }
}