package cz.muni.ics.oauth2.model.proxied_introspection.auth;

import cz.muni.ics.oidc.exceptions.ConfigurationException;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.Properties;

import static java.nio.charset.StandardCharsets.*;

/**
 * Authentication to remote introspection endpoint using post body.
 *
 * Configuration of providers (replace [name] part with the name defined for the endpoint):
 * <ul>
 *     <li><b>proxied_introspection.provider.[name].username</b> - username (non-blank string)</li>
 *     <li><b>proxied_introspection.provider.[name].username_param</b> - name of the username parameter, defaults
 *         to `client_id`</li>
 *     <li><b>proxied_introspection.provider.[name].password</b> - password (can be blank)</li>
 *     <li><b>proxied_introspection.provider.[name].password_param</b> - name of the password parameter, defaults
 *         to `client_secret`</li>
 * </ul>
 *
 * @see cz.muni.ics.oauth2.model.proxied_introspection.ProxiedIntrospectionEndpoint
 *
 * @author Dominik Frantisek Bucik <bucik@ics.muni.cz>
 */
public class ClientCredentialsViaBodyProxiedIntrospectionAuthMethod implements ProxiedIntrospectionEndpointAuthMethod {

    public static final String USERNAME = "username";
    public static final String USERNAME_PARAM = "username_param";
    public static final String PASSWORD = "password";
    public static final String PASSWORD_PARAM = "password_param";

    private final String username;

    private final String usernameParam;

    private final String password;

    private final String passwordParam;

    public ClientCredentialsViaBodyProxiedIntrospectionAuthMethod(String propertyBase, Properties properties) {
        this.username = properties.getProperty(propertyBase + USERNAME, "");
        if (!StringUtils.hasText(this.username)) {
            throw new ConfigurationException("No username configured");
        }
        this.usernameParam = properties.getProperty(propertyBase + USERNAME_PARAM, "client_id");
        this.password = properties.getProperty(propertyBase + PASSWORD, "");
        this.passwordParam = properties.getProperty(propertyBase + PASSWORD_PARAM, "client_secret");
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        if (request.getMethod() == HttpMethod.POST) {
            String bodyStr = new String(body, UTF_8);
            bodyStr += URLEncoder.encode(usernameParam, UTF_8) + '=' + URLEncoder.encode(username, UTF_8);
            bodyStr += '&';
            bodyStr += URLEncoder.encode(passwordParam, UTF_8) + '=' + URLEncoder.encode(password, UTF_8);
            body = bodyStr.getBytes(UTF_8);
        }
        return execution.execute(request, body);
    }
}
