package eu.eudat.logic.security.customproviders.B2Access;

import com.google.api.client.repackaged.org.apache.commons.codec.binary.Base64;
import eu.eudat.logic.security.validators.b2access.helpers.B2AccessResponseToken;
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.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.Map;

@Component("b2AccessCustomProvider")
public class B2AccessCustomProviderImpl implements B2AccessCustomProvider {

    private Environment environment;

    @Autowired
    public B2AccessCustomProviderImpl(Environment environment) {
        this.environment = environment;
    }

    public B2AccessUser getUser(String accessToken) {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = this.createBearerAuthHeaders(accessToken);
        HttpEntity<String> entity = new HttpEntity<>(headers);

        Map<String, Object> values = restTemplate.exchange(this.environment.getProperty("b2access.externallogin.user_info_url"), HttpMethod.GET, entity, Map.class).getBody();
        B2AccessUser b2AccessUser = new B2AccessUser();
        b2AccessUser.setEmail((String)values.get("email"));
        b2AccessUser.setId((String)values.get("urn:oid:2.5.4.49"));
        b2AccessUser.setName((String)values.get("name"));
        return b2AccessUser;
    }

    @Override
    public B2AccessResponseToken getAccessToken(String code, String redirectUri, String clientId, String clientSecret) {
        RestTemplate template = new RestTemplate();
        HttpHeaders headers = this.createBasicAuthHeaders(clientId, clientSecret);
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.add("code", code);
        map.add("grant_type", "authorization_code");
        map.add("redirect_uri", redirectUri);
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);

        Map<String, Object> values = template.postForObject(this.environment.getProperty("b2access.externallogin.access_token_url"), request, Map.class);
        B2AccessResponseToken b2AccessResponseToken = new B2AccessResponseToken();
        b2AccessResponseToken.setAccessToken((String) values.get("access_token"));
        return b2AccessResponseToken;
    }

    private HttpHeaders createBasicAuthHeaders(String username, String password) {
        return new HttpHeaders() {{
            String auth = username + ":" + password;
            byte[] encodedAuth = Base64.encodeBase64(
                    auth.getBytes(Charset.forName("US-ASCII")));
            String authHeader = "Basic " + new String(encodedAuth);
            set("Authorization", authHeader);
        }};
    }

    private HttpHeaders createBearerAuthHeaders(String accessToken) {
        return new HttpHeaders() {{
            String authHeader = "Bearer " + new String(accessToken);
            set("Authorization", authHeader);
        }};
    }
}
