package org.keycloak.testsuite.util.oauth;

import java.io.IOException;
import java.util.List;

import org.keycloak.OAuth2Constants;
import org.keycloak.protocol.oid4vc.model.OID4VCAuthorizationDetail;
import org.keycloak.util.JsonSerialization;
import org.keycloak.util.TokenUtil;

import org.apache.http.client.methods.CloseableHttpResponse;

public class AccessTokenRequest extends AbstractHttpPostRequest<AccessTokenRequest, AccessTokenResponse> {

    private final String code;

    public AccessTokenRequest(AbstractOAuthClient<?> client, String code) {
        super(client);
        this.code = code;
    }

    @Override
    protected String getEndpoint() {
        return client.getEndpoints().getToken();
    }

    public AccessTokenRequest signedJwt(String signedJwt) {
        parameter(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT);
        parameter(OAuth2Constants.CLIENT_ASSERTION, signedJwt);
        return this;
    }

    public AccessTokenRequest codeVerifier(PkceGenerator pkceGenerator) {
        if (pkceGenerator != null) {
            codeVerifier(pkceGenerator.getCodeVerifier());
        }
        return this;
    }

    public AccessTokenRequest codeVerifier(String codeVerifier) {
        parameter(OAuth2Constants.CODE_VERIFIER, codeVerifier);
        return this;
    }

    public AccessTokenRequest authorizationDetails(List<OID4VCAuthorizationDetail> authDetails) {
        parameter(OAuth2Constants.AUTHORIZATION_DETAILS, JsonSerialization.valueAsString(authDetails));
        return this;
    }

    public AccessTokenRequest dpopProof(String dpopProof) {
        header(TokenUtil.TOKEN_TYPE_DPOP, dpopProof);
        return this;
    }

    public AccessTokenRequest redirectUri(String redirectUri) {
        parameter(OAuth2Constants.REDIRECT_URI, redirectUri);
        return this;
    }

    public AccessTokenRequest resource(String resource) {
        parameter(OAuth2Constants.RESOURCE, resource);
        return this;
    }

    public AccessTokenRequest param(String name, String value) {
        parameter(name, value);
        return this;
    }

    protected void initRequest() {
        parameter(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE);
        parameter(OAuth2Constants.CODE, code);
        if (!hasParameter(OAuth2Constants.REDIRECT_URI)) {
            parameter(OAuth2Constants.REDIRECT_URI, client.getRedirectUri());
        }
    }

    @Override
    protected AccessTokenResponse toResponse(CloseableHttpResponse response) throws IOException {
        return new AccessTokenResponse(response);
    }
}
