package fr.ydelouis.selfoss.rest;

import android.net.Uri;
import android.util.Log;

import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;

import fr.ydelouis.selfoss.BuildConfig;
import fr.ydelouis.selfoss.account.SelfossAccount;
import fr.ydelouis.selfoss.util.Streams;

@EBean
public class SelfossApiInterceptor implements ClientHttpRequestInterceptor {

	private static final String TAG = "Selfoss API";
	private static final String KEY_USERNAME = "username";
	private static final String KEY_PASSWORD = "password";
	private static boolean LOG_REQUEST = BuildConfig.DEBUG && true;
	private static boolean LOG_FULL_REQUEST = BuildConfig.DEBUG && true;
	private static boolean LOG_RESPONSE = BuildConfig.DEBUG && true;

	@Bean protected SelfossAccount account;

	public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
		HttpRequest apiRequest = new ApiHttpRequest(request);
		logRequest(apiRequest);
		ApiHttpResponse response = new ApiHttpResponse(execution.execute(apiRequest, body));
		logResponse(response);
		return response;
	}

	private void logResponse(ApiHttpResponse response) throws IOException {
		if(LOG_RESPONSE)
			Log.i(TAG, response.getStatusCode().value() + " : " + Streams.stringOf(response.getBody()));
	}

	private void logRequest(HttpRequest request) throws UnsupportedEncodingException {
		String requestUri = URLDecoder.decode(request.getURI().toString(), "UTF-8");
		if(!LOG_FULL_REQUEST && LOG_REQUEST) {
			int start = requestUri.indexOf(account.getUrl());
			if (start > 0) {
				requestUri = requestUri.substring(start);
			}
		}
		requestUri = hidePassword(requestUri);
		Log.i(TAG, request.getMethod() + " : " + requestUri);
	}

	private String hidePassword(String requestUri) {
		return requestUri.replace(Uri.encode(account.getPassword()), "************");
	}

	private class ApiHttpRequest implements HttpRequest
	{
		private HttpRequest httpRequest;

		public ApiHttpRequest(HttpRequest httpRequest) {
			this.httpRequest = httpRequest;
			this.httpRequest.getHeaders().set("Content-Length", "0");
			this.httpRequest.getHeaders().remove("Content-Type");
		}

		@Override
		public HttpHeaders getHeaders() {
			return httpRequest.getHeaders();
		}

		@Override
		public HttpMethod getMethod() {
			return httpRequest.getMethod();
		}

		@Override
		public URI getURI() {
			URI uri = httpRequest.getURI();
			Uri.Builder builder = new Uri.Builder();
			builder.scheme(getScheme());
			builder.authority(account.getUrl());
			builder.path(uri.getPath());
			builder.encodedQuery(uri.getQuery());
			if (account.requireAuth()) {
				builder.appendQueryParameter(KEY_USERNAME, account.getUsername());
				builder.appendQueryParameter(KEY_PASSWORD, account.getPassword());
			}
			Uri newUri = builder.build();
			String uriStr = newUri.toString().replace(newUri.getEncodedAuthority(), newUri.getAuthority());
			System.out.println(uriStr);
			return URI.create(uriStr);
		}

		private String getScheme() {
			return account.useHttps() ? "https" : "http";
		}
	}

	private class ApiHttpResponse implements ClientHttpResponse
	{
		private ClientHttpResponse response;
		private byte[] byteResponse;

		public ApiHttpResponse(ClientHttpResponse response) {
			try {
				this.response = response;
				this.response.getHeaders().set("Content-Type", "application/json");
				byteResponse = Streams.byteArrayOf(response.getBody());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		@Override
		public InputStream getBody() throws IOException {
			return new ByteArrayInputStream(byteResponse);
		}

		@Override
		public HttpHeaders getHeaders() {
			return response.getHeaders();
		}

		@Override
		public void close() {
			response.close();
		}

		@Override
		public int getRawStatusCode() throws IOException {
			return response.getRawStatusCode();
		}

		@Override
		public HttpStatus getStatusCode() throws IOException {
			return response.getStatusCode();
		}

		@Override
		public String getStatusText() throws IOException {
			return response.getStatusText();
		}
	}
}


@@ -1238,35 +1238,36 @@
 Config.DEBUG && 
-tru
+fals
 e;%0A%09private stat
@@ -1313,19 +1313,20 @@
 EBUG && 
-tru
+fals
 e;%0A%0A%09@Be
@@ -2106,16 +2106,50 @@
 UEST) %7B%0A
+%09%09%09String url = account.getUrl();%0A
 %09%09%09int s
@@ -2174,32 +2174,19 @@
 indexOf(
-account.getUrl()
+url
 );%0A%09%09%09if
@@ -2197,11 +2197,13 @@
 art 
-%3E 0
+!= -1
 ) %7B%0A
@@ -2245,16 +2245,29 @@
 ng(start
++url.length()
 );%0A%09%09%09%7D%0A
@@ -2453,19 +2453,8 @@
 ace(
-Uri.encode(
 acco
@@ -2470,17 +2470,16 @@
 ssword()
-)
 , %22*****
@@ -3441,16 +3441,16 @@
 uild();%0A
+
 %09%09%09Strin
@@ -3544,39 +3544,8 @@
 ));%0A
-%09%09%09System.out.println(uriStr);%0A
 %09%09%09r

Fix request log.