package eu.eudat.core.logger.remote.http;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import eu.eudat.core.logger.Logger;
import eu.eudat.core.logger.common.AbstractBatchLogger;
import eu.eudat.core.models.LoggingModel;
import eu.eudat.core.models.exception.ApiExceptionLoggingModel;
import eu.eudat.core.models.exception.ExceptionLoggingModel;
import eu.eudat.core.models.simple.SimpleAuditModel;
import eu.eudat.core.models.simple.SimpleLoggingModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import types.LoggingOutputType;
import types.LoggingType;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by ikalyvas on 5/30/2018.
 */

//@Service("logger")
public class HttpRemoteLogger extends AbstractBatchLogger implements Logger {

    private RestTemplate rest;
    private HttpHeaders headers;
    private Environment environment;

    //@Autowired
    public HttpRemoteLogger(Environment environment) {
        super(environment);
        this.rest = new RestTemplate();
        this.headers = new HttpHeaders();
        this.environment = environment;
        headers.add("Content-Type", "application/json");
        headers.add("Accept", "*/*");
    }

    @Override
    public void outputData() {
        try {
            String log = this.tranformLog();
            if (log != null) {
                HttpEntity<String> requestEntity = new HttpEntity(log, headers);
                ResponseEntity<String> Object = rest.exchange(this.environment.getProperty("http-logger.server-address"), HttpMethod.POST, requestEntity, String.class);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    @Override
    public LoggingOutputType logOutputType() {
        return LoggingOutputType.JSON;
    }

    @Override
    public <T> void debug(T model) {
        LoggingModel<T> loggingModel = new SimpleLoggingModel<>();
        loggingModel.setData(model);
        loggingModel.setType(LoggingType.DEBUG);
        this.put(String.valueOf(model.hashCode()), loggingModel);
    }

    @Override
    public <T> void debug(T model, String message) {
        LoggingModel<T> loggingModel = new SimpleLoggingModel<>();
        loggingModel.setData(model);
        loggingModel.setMessage(message);
        loggingModel.setType(LoggingType.DEBUG);
        this.put(String.valueOf(model.hashCode()), loggingModel);
    }

    @Override
    public <T> void debug(String message) {
        LoggingModel<T> loggingModel = new SimpleLoggingModel<>();
        loggingModel.setMessage(message);
        loggingModel.setType(LoggingType.DEBUG);
        this.put(String.valueOf(message.hashCode()), loggingModel);
    }

    @Override
    public <T extends Exception> void debug(T exception) {
        ExceptionLoggingModel exceptionLoggingModel = new ExceptionLoggingModel();
        Map<String, String> map = new HashMap<>();
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
            String json = ow.writeValueAsString(exception);
            map.put("exception", json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        exceptionLoggingModel.setData(map);
        exceptionLoggingModel.setType(LoggingType.DEBUG);
        this.put(String.valueOf(exception.hashCode()), exceptionLoggingModel);
    }

    @Override
    public <T extends Exception> void debug(T exception, String message) {
        ExceptionLoggingModel exceptionLoggingModel = new ExceptionLoggingModel();
        Map<String, String> map = new HashMap<>();
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
            String json = ow.writeValueAsString(exception);
            map.put("exception", json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        exceptionLoggingModel.setData(map);
        exceptionLoggingModel.setMessage(message);
        exceptionLoggingModel.setType(LoggingType.DEBUG);
        this.put(String.valueOf(exception.hashCode()), exceptionLoggingModel);
    }

    @Override
    public <T> void warn(T model) {
        LoggingModel<T> loggingModel = new SimpleLoggingModel<>();
        loggingModel.setData(model);
        loggingModel.setType(LoggingType.WARNING);
        this.put(String.valueOf(model.hashCode()), loggingModel);
    }

    @Override
    public <T> void warn(T model, String message) {
        LoggingModel<T> loggingModel = new SimpleLoggingModel<>();
        loggingModel.setData(model);
        loggingModel.setMessage(message);
        loggingModel.setType(LoggingType.WARNING);
        this.put(String.valueOf(model.hashCode()), loggingModel);
    }

    @Override
    public <T> void warn(String message) {
        LoggingModel<T> loggingModel = new SimpleLoggingModel<>();
        loggingModel.setMessage(message);
        loggingModel.setType(LoggingType.WARNING);
        this.put(String.valueOf(message.hashCode()), loggingModel);
    }

    @Override
    public <T extends Exception> void warn(T exception) {
        ExceptionLoggingModel exceptionLoggingModel = new ExceptionLoggingModel();
        Map<String, String> map = new HashMap<>();
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
            String json = ow.writeValueAsString(exception);
            map.put("exception", json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        exceptionLoggingModel.setData(map);
        exceptionLoggingModel.setType(LoggingType.WARNING);
        this.put(String.valueOf(exception.hashCode()), exceptionLoggingModel);
    }

    @Override
    public <T extends Exception> void warn(T exception, String message) {
        ExceptionLoggingModel exceptionLoggingModel = new ExceptionLoggingModel();
        Map<String, String> map = new HashMap<>();
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
            String json = ow.writeValueAsString(exception);
            map.put("exception", json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        exceptionLoggingModel.setData(map);
        exceptionLoggingModel.setMessage(message);
        exceptionLoggingModel.setType(LoggingType.WARNING);
        this.put(String.valueOf(exception.hashCode()), exceptionLoggingModel);
    }

    @Override
    public <T> void info(String message) {
        SimpleAuditModel<T> simpleAuditModel = new SimpleAuditModel<>();
        simpleAuditModel.setMessage(message);
        simpleAuditModel.setType(LoggingType.INFO);
        this.put(String.valueOf(simpleAuditModel.hashCode()), simpleAuditModel);
    }

    @Override
    public <T> void info(T model) {
        SimpleAuditModel<T> simpleAuditModel = new SimpleAuditModel<>();
        simpleAuditModel.setData(model);
        simpleAuditModel.setType(LoggingType.INFO);
        this.put(String.valueOf(model.hashCode()), simpleAuditModel);
    }

    @Override
    public <T> void info(T model, String message) {
        SimpleAuditModel<T> simpleAuditModel = new SimpleAuditModel<>();
        simpleAuditModel.setData(model);
        simpleAuditModel.setMessage(message);
        simpleAuditModel.setType(LoggingType.INFO);
        this.put(String.valueOf(model.hashCode()), simpleAuditModel);
    }

    @Override
    public <T extends RuntimeException> void info(T exception) {
        ExceptionLoggingModel exceptionLoggingModel = new ExceptionLoggingModel();
        Map<String, String> map = new HashMap<>();
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
            String json = ow.writeValueAsString(exception);
            map.put("exception", json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        exceptionLoggingModel.setData(map);
        exceptionLoggingModel.setType(LoggingType.INFO);
        this.put(String.valueOf(exception.hashCode()), exceptionLoggingModel);
    }

    @Override
    public <T extends RuntimeException> void info(T exception, String message) {
        ExceptionLoggingModel exceptionLoggingModel = new ExceptionLoggingModel();
        Map<String, String> map = new HashMap<>();
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
            String json = ow.writeValueAsString(exception);
            map.put("exception", json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        exceptionLoggingModel.setData(map);
        exceptionLoggingModel.setMessage(message);
        exceptionLoggingModel.setType(LoggingType.INFO);
        this.put(String.valueOf(exception.hashCode()), exceptionLoggingModel);
    }

    @Override
    public <E extends Exception, P> void error(ApiExceptionLoggingModel<E, P> model) {
        this.put(String.valueOf(model.hashCode()), model);
    }

    @Override
    public <T> void error(T model) {
        LoggingModel<T> loggingModel = new SimpleLoggingModel<>();
        loggingModel.setType(LoggingType.DEBUG);
        loggingModel.setData(model);
        this.put(String.valueOf(model.hashCode()), loggingModel);
    }

    @Override
    public <T extends Exception> void error(T exception) {
        ExceptionLoggingModel exceptionLoggingModel = new ExceptionLoggingModel();
        Map<String, String> map = new HashMap<>();
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
            String json = ow.writeValueAsString(exception);
            map.put("exception", json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        exceptionLoggingModel.setData(map);
        exceptionLoggingModel.setType(LoggingType.ERROR);
        this.put(String.valueOf(exception.hashCode()), exceptionLoggingModel);
    }

    @Override
    public <T extends Exception> void error(T exception, String message) {
        ExceptionLoggingModel exceptionLoggingModel = new ExceptionLoggingModel();
        Map<String, String> map = new HashMap<>();
        ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
        try {
            String json = ow.writeValueAsString(exception);
            map.put("exception", json);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        exceptionLoggingModel.setData(map);
        exceptionLoggingModel.setMessage(message);
        exceptionLoggingModel.setType(LoggingType.ERROR);
        this.put(String.valueOf(exception.hashCode()), exceptionLoggingModel);
    }
}
