package org.bench4q.agent.test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import static org.junit.Assert.*;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.io.FileUtils;
import org.bench4q.agent.plugin.ParameterFileCollector;
import org.bench4q.share.communication.HttpRequester;
import org.bench4q.share.communication.HttpRequester.HttpResponse;
import org.bench4q.share.helper.MarshalHelper;
import org.bench4q.share.helper.TestHelper;
import org.bench4q.share.models.agent.BehaviorBriefModel;
import org.bench4q.share.models.agent.RunScenarioModel;
import org.bench4q.share.models.agent.RunScenarioResultModel;
import org.bench4q.share.models.agent.statistics.AgentBriefStatusModel;
import org.bench4q.share.models.agent.statistics.AgentBehaviorsBriefModel;
import org.bench4q.share.models.agent.statistics.AgentPageBriefModel;
import org.junit.Test;

public class TestWithScriptFile extends TestBase {
	private HttpRequester httpRequester;
	private String url = "http://localhost:6565/test";
	private String filePath;
	private UUID testId;
	private static int load = 10;

	private String getFilePath() {
		return filePath;
	}

	private void setFilePath(String filePath) {
		this.filePath = filePath;
	}

	private HttpRequester getHttpRequester() {
		return httpRequester;
	}

	private void setHttpRequester(HttpRequester httpRequester) {
		this.httpRequester = httpRequester;
	}

	private UUID getTestId() {
		return testId;
	}

	private void setTestId(UUID testId) {
		this.testId = testId;
	}

	public TestWithScriptFile() {
		this.setFilePath("Scripts" + System.getProperty("file.separator")
				+ "homepage.xml");
		this.setHttpRequester(new HttpRequester());
	}

	private void startTest() throws JAXBException {
		try {
			RunScenarioModel runScenarioModel = getScenarioModel();
			if (runScenarioModel == null) {
				System.out.println("can't execute an invalid script");
				return;
			}
			assertTrue(runScenarioModel.getPages().size() > 0);
			assertTrue(runScenarioModel.getPages().get(0).getBatches().get(0)
					.getBehaviors().size() > 0);

			HttpResponse httpResponse = this.getHttpRequester().sendPostXml(
					this.url + "/runWithoutParams",
					marshalRunScenarioModel(runScenarioModel), null);
			RunScenarioResultModel resultModel = (RunScenarioResultModel) MarshalHelper
					.unmarshal(RunScenarioResultModel.class,
							httpResponse.getContent());
			this.setTestId(resultModel.getRunId());
		} catch (IOException e) {
			System.out.println("IO exception!");
		}
	}

	private RunScenarioModel getScenarioModel() throws IOException {
		String scriptContent;
		File file = new File(this.getFilePath());
		if (!file.exists()) {
			System.out.println("this script not exists!");
			return null;
		}
		scriptContent = FileUtils.readFileToString(file);
		RunScenarioModel runScenarioModel = extractRunScenarioModel(scriptContent);
		runScenarioModel.setPoolSize(load);
		return runScenarioModel;
	}

	private RunScenarioModel extractRunScenarioModel(String scriptContent) {
		try {
			Unmarshaller unmarshaller = JAXBContext.newInstance(
					RunScenarioModel.class).createUnmarshaller();
			return (RunScenarioModel) unmarshaller
					.unmarshal(new ByteArrayInputStream(scriptContent
							.getBytes()));
		} catch (JAXBException e) {
			System.out.println("model unmarshal has an exception!");
			e.printStackTrace();
			return null;
		}

	}

	private String marshalRunScenarioModel(RunScenarioModel model)
			throws JAXBException {
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		JAXBContext.newInstance(RunScenarioModel.class).createMarshaller()
				.marshal(model, outputStream);
		return outputStream.toString();
	}

	private void stopTest() throws IOException {
		System.out.println("Enter stopTest!");
		this.getHttpRequester().sendGet(
				this.url + "/stop/" + this.getTestId().toString(), null, null);
	}

	private void scenarioBrief() throws IOException, JAXBException {
		System.out.println("Enter brief!");
		HttpResponse httpResponse = this.getHttpRequester().sendGet(
				this.url + "/brief/" + this.getTestId().toString(), null, null);
		System.out.println(httpResponse.getContent());
		AgentBriefStatusModel briefModel = (AgentBriefStatusModel) MarshalHelper
				.unmarshal(AgentBriefStatusModel.class,
						httpResponse.getContent());
		assertTrue(briefModel.getTimeFrame() > 0);
	}

	private void behaviorsBrief() throws IOException, JAXBException {
		System.out.println("Enter behaviorsBrief!");
		HttpResponse httpResponse = this.getHttpRequester().sendGet(
				this.url + "/behaviorsBrief/" + this.getTestId().toString(),
				null, null);
		System.out.println(httpResponse.getContent());
		AgentBehaviorsBriefModel behaviorsBriefModel = (AgentBehaviorsBriefModel) MarshalHelper
				.unmarshal(AgentBehaviorsBriefModel.class,
						httpResponse.getContent());
		assertTrue(behaviorsBriefModel.getBehaviorBriefModels().size() > 0);
	}

	private void behaviorBrief() throws IOException, JAXBException {
		System.out.println("Enter behaviorBrief!");
		HttpResponse httpResponse = this.getHttpRequester().sendGet(
				this.url + "/brief/" + this.getTestId().toString() + "/0",
				null, null);
		BehaviorBriefModel behaviorBriefModel = (BehaviorBriefModel) MarshalHelper
				.unmarshal(BehaviorBriefModel.class, httpResponse.getContent());
		assertTrue(behaviorBriefModel.getDetailStatusCodeResultModels().size() > 0);
	}

	@Test
	public void integrateTest() throws JAXBException, InterruptedException,
			IOException {
		try {
			this.startTest();
			Thread.sleep(5000);
			this.scenarioBrief();
			Thread.sleep(5000);
			this.behaviorsBrief();
			Thread.sleep(5000);
			this.behaviorBrief();
			Thread.sleep(5000);
			this.pageBrief(0);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			this.stopTest();
		}

	}

	@Test
	public void testSubmitParamsAndRun() throws Exception {
		List<File> files = new ArrayList<File>();
		files.add(new File("Scripts" + System.getProperty("file.separator")
				+ "testForBrief.xml"));
		files.add(new File("Scripts" + System.getProperty("file.separator")
				+ "testJD.xml"));
		HttpResponse httpResponse1 = this.getHttpRequester().sendPost(
				url + "/bookTest/20", null, null);
		RunScenarioResultModel bookResponse = (RunScenarioResultModel) MarshalHelper
				.tryUnmarshal(RunScenarioResultModel.class,
						httpResponse1.getContent());
		assertNotNull(bookResponse);
		assertNotNull(bookResponse.getRunId().toString());
		System.out.println(bookResponse.getRunId().toString());
		Map<String, String> stringPart = new LinkedHashMap<String, String>();
		stringPart.put("scenarioModel",
				MarshalHelper.tryMarshal(getScenarioModel()));
		stringPart.put("scheduleContent",
				MarshalHelper.tryMarshal(buildScheduleModel()));
		// TODO:
		HttpResponse httpResponse = this.getHttpRequester().postFiles(
				null,
				url + "/submitScenarioWithParams/"
						+ bookResponse.getRunId().toString() + "/"
						+ new Date().getTime(), "files[]", files, stringPart);
		assertNotNull(httpResponse);
		assertNotNull(httpResponse.getContent());
		assertEquals(200, httpResponse.getCode());
		RunScenarioResultModel resultModel = (RunScenarioResultModel) MarshalHelper
				.tryUnmarshal(RunScenarioResultModel.class,
						httpResponse.getContent());
		String dirPath = (String) TestHelper.invokePrivate(
				new ParameterFileCollector(), "guardDirExists",
				new Class[] { UUID.class },
				new Object[] { resultModel.getRunId() });
		File file = new File(dirPath);
		assertTrue(file.exists());
		assertEquals(2, file.listFiles().length);
		System.out.println(httpResponse.getContent());

		httpResponse = this.getHttpRequester().sendPost(
				this.url + "/runWithParams/"
						+ resultModel.getRunId().toString(), null, null);
		assertNotNull(httpResponse);
		System.out.println(httpResponse.getContent());
	}

	private void pageBrief(int i) throws IOException, JAXBException {
		try {
			HttpResponse httpResponse = this.getHttpRequester().sendGet(
					url + "/pageBrief/" + this.getTestId() + "/" + i, null,
					null);
			if (httpResponse == null || httpResponse.getContent().isEmpty()) {
				fail();
			}
			System.out.println(httpResponse);
			AgentPageBriefModel pageBriefModel = (AgentPageBriefModel) MarshalHelper
					.unmarshal(AgentPageBriefModel.class,
							httpResponse.getContent());
			assertTrue(pageBriefModel.getCountFromBegin() > 0);
		} catch (Exception e) {
			this.stopTest();
		}

	}

	@Test
	public void testHBasePluginScenario() throws IOException {
		String scenarioContent = FileUtils.readFileToString(new File(
				"Scripts/HBaseScript.xml"));
		HttpResponse httpResponse = this.getHttpRequester().sendPostXml(
				url + "/runWithoutParams", scenarioContent, null);
		assertFalse(HttpRequester.isInvalidResponse(httpResponse));
	}
}
