package be.jeffcheasey88.peeratcode.webclient;

import static org.junit.Assert.fail;

import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.simple.JSONObject;

import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;

public class WebClient {
	
	private static Pattern AUTORIZATION = Pattern.compile("Authorization: Bearer (.*)");
	
	private Socket socket;
	private HttpReader reader;
	private HttpWriter writer;
	
	private String token;
	private int responseCode;
	private List<String> headers;
	private List<String> content;
	
	public List<String> sendHeaders = new ArrayList<>();
	
	private String host;
	private int port;
	
	public WebClient(String host, int port){
		this.host = host;
		this.port = port;
		this.headers = new ArrayList<>();
		this.content = new ArrayList<>();
	}
	
	private void ensureConnection() throws Exception{
		this.socket = new Socket(this.host, this.port);
		this.reader = new HttpReader(socket);
		this.writer = new HttpWriter(socket);
		this.responseCode = -1;
		this.headers.clear();
		this.content.clear();
	}
	
	public void auth(String user, String password) throws Exception{
		JSONObject login = new JSONObject();
		login.put("pseudo", user);
		login.put("passwd", password);
		route("/login", "POST", login.toJSONString());
		System.out.println("["+host+"] /login "+login);
		
		for(String line : this.headers){
			Matcher matcher = AUTORIZATION.matcher(line);
			if(matcher.matches()){
				this.token = matcher.group(1);
				System.out.println(host+": "+token);
				break;
			}
			System.out.println("["+host+"] "+line);
		}
	}
	
	public void register(String user, String password, String email, String firstname, String lastname, String description) throws Exception{
		JSONObject register = new JSONObject();
		register.put("pseudo", user);
		register.put("passwd", password);
		register.put("email", email);
		register.put("firstname", firstname);
		register.put("lastname", lastname);
		register.put("description", description);
		register.put("sgroup", "");
		register.put("avatar", "");
		
		route("/register", "POST", register.toJSONString());
		System.out.println("["+host+"] /register "+register);
		for(String line : this.headers){
			Matcher matcher = AUTORIZATION.matcher(line);
			if(matcher.matches()){
				this.token = matcher.group(1);
				System.out.println(host+": "+token);
				break;
			}
			System.out.println("["+host+"] "+line);
		}
	}
	
	public void disconnect(){
		this.token = null;
	}
	
	public void route(String route, String type, String... content) throws Exception{
		ensureConnection();
		this.writer.write(type+" "+route+" HTTP/1.1\n");
		if(this.token != null) this.writer.write("Authorization: Bearer "+this.token+"\n");
		for(String send : this.sendHeaders) this.writer.write(send+"\n");
		
		this.writer.write("\n");
		for(String value : content) this.writer.write(value+"\n");
		this.writer.flush();
		
		String t = this.reader.readLine();
		System.out.println(t);
		this.responseCode = Integer.parseInt(t.split("\\s+")[1]);
		String line;
		while(((line = reader.readLine()) != null) && line.length() > 0) this.headers.add(line);
		
		while((line = reader.readLine()) != null) this.content.add(line);
		
		System.out.println(Arrays.toString(this.content.toArray(new String[0])));
	}
	
	public void assertResponseCode(int expected){
		try {
			if(expected != responseCode) fail("Expected http reponse code <"+expected+"> but found <"+responseCode+">");
		} catch (Exception e){
			fail("Failed to get the response code: "+e.getMessage());
		}
	}
	
	public void assertHeader(String expected){
		for(String header : headers){
			if(header.equals(expected)) return;
		}
		fail("Line <"+expected+"> not found in "+this.headers.size()+" headers");
	}
	
	public static String[] buildMultiPartData(String... datas){
		if(datas == null) return new String[0];
		String[] result = new String[1+(4*datas.length)];
		int index = 0;
		for(String data : datas){
			result[index++] = "------WebKitFormBoundaryNUjiLBAMuX2dhxU7";
			result[index++] = "Content-Disposition: form-data; name=\"?\"";
			result[index++] = "";
			result[index++] = data;
		}
		result[index++] = "------WebKitFormBoundaryNUjiLBAMuX2dhxU7";
		return result;
	}
}
