package cz.senslog.connector.push.theros;

import com.google.gson.JsonObject;
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.tools.json.BasicJson;
import cz.senslog.connector.tools.json.JsonUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import static cz.senslog.connector.tools.http.HttpContentType.APPLICATION_FORM_URLENCODED;
import static cz.senslog.connector.tools.http.HttpHeader.CONTENT_TYPE;

public class AuthService {

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

    private final AuthConfig config;

    private final HttpClient httpClient;

    private final String credentials;

    private AuthorizationToken authorizationToken;

    AuthService(AuthConfig config, HttpClient httpClient) {
        this.config = config;
        this.httpClient = httpClient;

        JsonObject credentialsJson = new JsonObject();
        credentialsJson.addProperty("client_id", config.getClientId());
        credentialsJson.addProperty("client_secret", config.getClientSecret());
        credentialsJson.addProperty("grant_type", "client_credentials");
        credentialsJson.addProperty("username", config.getUsername());
        credentialsJson.addProperty("password", config.getPassword());

        this.credentials = JsonUtils.jsonObjectToFormURLEncodedString(credentialsJson);
        this.authorizationToken = null;
    }

    public synchronized boolean authenticate() {
        if (AuthorizationToken.isValid(authorizationToken)) {
            return true;
        }

        HttpRequest request = HttpRequest.newBuilder().POST()
                .url(URLBuilder.newBuilder(config.getUrl()).build())
                .header(CONTENT_TYPE, APPLICATION_FORM_URLENCODED)
                .body(credentials)
                .build();

        HttpResponse response = httpClient.send(request);

        if (response.isError()) {
            logger.error(response.getBody());
            authorizationToken = null;
        } else {
            JsonObject tokenInfoJson = BasicJson.jsonToObject(response.getBody(), JsonObject.class);
            authorizationToken = AuthorizationToken.of(
                    tokenInfoJson.get("access_token").getAsString(),
                    tokenInfoJson.get("token_type").getAsString(),
                    tokenInfoJson.get("scope").getAsString(),
                    tokenInfoJson.get("expires_in").getAsInt()
            );
        }

        return AuthorizationToken.isValid(authorizationToken);
    }

    public AuthorizationToken getAuthorizationToken() {
        if (AuthorizationToken.isValid(authorizationToken)) {
            return authorizationToken;
        }
        if (authenticate()) {
            return authorizationToken;
        }
        return null;
    }
}
