package gov.va.vinci.dart;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.stub;
import gov.va.vinci.dart.biz.DartRequest;
import gov.va.vinci.dart.biz.Request;
import gov.va.vinci.dart.common.SingletonShim;
import gov.va.vinci.dart.common.json.ErrorView;
import gov.va.vinci.dart.common.test.BusinessIntegrationTest;
import gov.va.vinci.dart.json.ActivityView;
import gov.va.vinci.dart.json.CreateActivityView;
import gov.va.vinci.dart.json.NewActivityView;
import gov.va.vinci.dart.json.PILocationView;
import gov.va.vinci.dart.json.PIParticipantView;
import gov.va.vinci.dart.json.PrimaryInfoView;
import gov.va.vinci.dart.json.RequestIdView;
import gov.va.vinci.dart.json.SaveActivityView;
import gov.va.vinci.dart.json.SavePrimaryInfoView;
import gov.va.vinci.dart.json.SetupView;
import gov.va.vinci.dart.mail.mock.MailManagerMock;
import gov.va.vinci.dart.service.DartObjectFactory;
import gov.va.vinci.dart.usr.CustomAuthentication;

import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;

import org.springframework.security.core.context.SecurityContextHolder;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class TestActivityController extends BusinessIntegrationTest {

	@BeforeTest
	public void setup() {
		SingletonShim.getBean(DartObjectFactory.class);
		
		CustomAuthentication token = new CustomAuthentication("DNS", null, "password", "details", "principal");

		try {
			DartObjectFactory.getInstance().getUserManager().login(token);
			SecurityContextHolder.getContext().setAuthentication(token);
		} 
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testOne() throws Exception {

		ActivityController ac = SingletonShim.getBean(ActivityController.class);

		HttpServletRequest request = mock(HttpServletRequest.class);
		Assert.assertNotNull(request);
		
		stub(request.getRequestURL()).toReturn(new StringBuffer("https://localhost:PORT/vinci_dart_client/dart/setup.json"));
		
		Object obj = ac.setup(request);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof SetupView);
		SetupView view = (SetupView)obj;
		
		// these values come from PersonDAOMock
		Assert.assertEquals(view.getUserId(), 1004);
		Assert.assertEquals(view.getUserLoginId(), "DNS");
		Assert.assertEquals(view.getUserFullName(), "DuBois, John (FVFT)");
		Assert.assertNotNull(view.getRoles());
		Assert.assertTrue(view.getRoles().size() > 0);
		Assert.assertNotNull(view.getGroups());
		Assert.assertTrue(view.getGroups().size() > 0);

		Assert.assertTrue(view.isAdmin());
		Assert.assertTrue(view.isNdsAdmin());
		Assert.assertFalse(view.isRequestor());
		Assert.assertFalse(view.isSuperUser());
	}

	@Test
	public void testTwo() throws Exception {

		CreateActivityView req = new CreateActivityView ();
		
		ActivityController ac = SingletonShim.getBean(ActivityController.class);

		// the request type is required
		Object obj = ac.createActivity(req);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		
		req.setType(Request.DATA_ACCESS);
		
		// official name is required
		obj = ac.createActivity(req);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);

		req.setOfficialName("official name");
		
		// now see if we can create it correctly
		obj = ac.createActivity(req);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof NewActivityView);
		
		NewActivityView nav = (NewActivityView)obj;
		Assert.assertTrue(nav.getActivityId() > 0);
		Assert.assertTrue(nav.getRequestId() > 0);
	}

	@Test
	public void testThree() throws Exception {

		CreateActivityView req = new CreateActivityView ();
		
		ActivityController ac = SingletonShim.getBean(ActivityController.class);

		req.setType(Request.DATA_ACCESS);
		req.setOfficialName("official name");
		
		// now see if we can create it correctly
		Object obj = ac.createActivity(req);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof NewActivityView);
		
		NewActivityView nav = (NewActivityView)obj;
		Assert.assertTrue(nav.getActivityId() > 0);
		Assert.assertTrue(nav.getRequestId() > 0);
		
		RequestIdView riv = new RequestIdView();
		
		riv.setUserId(1004);
		riv.setRequestId(nav.getRequestId());
		
		obj = ac.getActivityInfo(riv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ActivityView);
		
		ActivityView av = (ActivityView)obj;
		
		Assert.assertEquals(av.getType(), Request.DATA_ACCESS);
		Assert.assertEquals(av.getOfficialName(), "official name");
		Assert.assertEquals(av.getShortName(), "official name");  // if no short name given, the server returns the official name
		Assert.assertNull(av.getRequestSubmittedDate());
		Assert.assertNull(av.getActivityStartDate());
		Assert.assertNull(av.getActivityEndDate());
		Assert.assertNull(av.getiRBApprovalNumber());
		Assert.assertNull(av.getiRBExpirationDate());
	
		
		SaveActivityView sav = new SaveActivityView();
		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);

		sav.setRequestId(riv.getRequestId());
		sav.setShortName("short name");

		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertEquals(((ErrorView)obj).getMessage().get("text"), "OK");

		
		obj = ac.getActivityInfo(riv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ActivityView);
		
		av = (ActivityView)obj;
		Assert.assertEquals(av.getType(), Request.DATA_ACCESS);
		Assert.assertEquals(av.getOfficialName(), "official name");
		Assert.assertEquals(av.getShortName(), "short name");

		sav.setiRBExpirationDate("can't parse this date");
		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertNotEquals(((ErrorView)obj).getMessage().get("text"), "OK");
		
		sav.setiRBExpirationDate(null);
		sav.setActivityStartDate("can't parse this date");
		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertNotEquals(((ErrorView)obj).getMessage().get("text"), "OK");

		sav.setiRBExpirationDate(null);
		sav.setActivityStartDate(null);
		sav.setActivityEndDate("can't parse this date");
		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertNotEquals(((ErrorView)obj).getMessage().get("text"), "OK");

	}

	@Test
	public void testFour() throws Exception {

		CreateActivityView req = new CreateActivityView ();
		
		ActivityController ac = SingletonShim.getBean(ActivityController.class);

		req.setType(Request.OPERATIONS_DATA_ACCESS);
		req.setOfficialName("official name");
		
		// now see if we can create it correctly
		Object obj = ac.createActivity(req);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof NewActivityView);
		
		NewActivityView nav = (NewActivityView)obj;
		Assert.assertTrue(nav.getActivityId() > 0);
		Assert.assertTrue(nav.getRequestId() > 0);
		
		RequestIdView riv = new RequestIdView();
		
		riv.setUserId(1004);
		riv.setRequestId(nav.getRequestId());
		
		obj = ac.getActivityInfo(riv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ActivityView);
		
		ActivityView av = (ActivityView)obj;
		
		Assert.assertEquals(av.getType(), Request.OPERATIONS_DATA_ACCESS);
		Assert.assertEquals(av.getOfficialName(), "official name");
		Assert.assertEquals(av.getShortName(), "official name");  // if no short name given, the server returns the official name
		Assert.assertNull(av.getRequestSubmittedDate());
		Assert.assertNull(av.getActivityStartDate());
		Assert.assertNull(av.getActivityEndDate());
		Assert.assertNull(av.getiRBApprovalNumber());
		Assert.assertNull(av.getiRBExpirationDate());
	
		
		SaveActivityView sav = new SaveActivityView();
		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);

		sav.setRequestId(riv.getRequestId());
		sav.setShortName("short name");

		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertEquals(((ErrorView)obj).getMessage().get("text"), "OK");

		obj = ac.getActivityInfo(riv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ActivityView);
		
		av = (ActivityView)obj;
		Assert.assertEquals(av.getType(), Request.OPERATIONS_DATA_ACCESS);
		Assert.assertEquals(av.getOfficialName(), "official name");
		Assert.assertEquals(av.getShortName(), "short name");

		sav.setiRBExpirationDate("can't parse this date");
		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertNotEquals(((ErrorView)obj).getMessage().get("text"), "OK");
		
		sav.setiRBExpirationDate(null);
		sav.setActivityStartDate("can't parse this date");
		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertNotEquals(((ErrorView)obj).getMessage().get("text"), "OK");

		sav.setiRBExpirationDate(null);
		sav.setActivityStartDate(null);
		sav.setActivityEndDate("can't parse this date");
		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertNotEquals(((ErrorView)obj).getMessage().get("text"), "OK");

		sav.setActivityEndDate(null);

		sav.setJustification("justification");
		sav.setProgramOffice("program office");

		obj = ac.saveActivityInfo(sav);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertEquals(((ErrorView)obj).getMessage().get("text"), "OK");

		obj = ac.getActivityInfo(riv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ActivityView);
		
		av = (ActivityView)obj;
		Assert.assertNull(av.getiRBExpirationDate());
		Assert.assertNull(av.getActivityStartDate());
		Assert.assertNull(av.getActivityEndDate());
		Assert.assertEquals(av.getJustification(), "justification");
		Assert.assertEquals(av.getProgramOffice(), "program office");
	}

	@Test
	public void testFive() throws Exception {

		CreateActivityView req = new CreateActivityView ();
		
		ActivityController ac = SingletonShim.getBean(ActivityController.class);

		req.setType(Request.DATA_ACCESS);
		req.setOfficialName("official name");
		
		// now see if we can create it correctly
		Object obj = ac.createActivity(req);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof NewActivityView);
		
		NewActivityView nav = (NewActivityView)obj;
		Assert.assertTrue(nav.getActivityId() > 0);
		Assert.assertTrue(nav.getRequestId() > 0);
		
		RequestIdView riv = new RequestIdView();
		
		riv.setUserId(1004);
		riv.setRequestId(nav.getRequestId());
		
		obj = ac.getPrimaryInfo(riv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof PrimaryInfoView);
		
		PrimaryInfoView piv = (PrimaryInfoView)obj;
		Assert.assertNotNull(piv.getLocations());
		Assert.assertEquals(piv.getLocations().size(), 0);
		Assert.assertNotNull(piv.getInvestigators());
		Assert.assertEquals(piv.getInvestigators().size(), 0);
		
		SavePrimaryInfoView spiv = new SavePrimaryInfoView();
		spiv.setRequestId(nav.getRequestId());
		
		// you can save empty data
		obj = ac.savePrimaryInfo(spiv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertEquals(((ErrorView)obj).getMessage().get("text"), "OK");

		// you can set nothing
		piv.getLocations().clear();
		piv.getInvestigators().clear();
		spiv.setPrimaryInfo(piv);
		obj = ac.savePrimaryInfo(spiv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertEquals(((ErrorView)obj).getMessage().get("text"), "OK");
		
		// and you get nothing back
		obj = ac.getPrimaryInfo(riv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof PrimaryInfoView);
		
		piv = (PrimaryInfoView)obj;
		Assert.assertNotNull(piv.getLocations());
		Assert.assertEquals(piv.getLocations().size(), 0);
		Assert.assertNotNull(piv.getInvestigators());
		Assert.assertEquals(piv.getInvestigators().size(), 0);

		// give the activity a location
		PILocationView pilv = new PILocationView();
		pilv.setLocationId(26);
		piv.getLocations().add(pilv);
		piv.getInvestigators().clear();
		spiv.setPrimaryInfo(piv);
		obj = ac.savePrimaryInfo(spiv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof ErrorView);
		Assert.assertEquals(((ErrorView)obj).getMessage().get("text"), "OK");
		

		// and you get that location back
		riv.setRequestId(nav.getRequestId());
		obj = ac.getPrimaryInfo(riv);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof PrimaryInfoView);
		
		piv = (PrimaryInfoView)obj;
		Assert.assertNotNull(piv.getLocations());
		Assert.assertEquals(piv.getLocations().size(), 1);
		Assert.assertNotNull(piv.getInvestigators());
		Assert.assertEquals(piv.getInvestigators().size(), 1);  // there will be an empty participants container for the 1 location  
		Integer i = piv.getInvestigators().keySet().iterator().next();
		PIParticipantView pipv2 = piv.getInvestigators().get(i);
		Assert.assertNotNull(pipv2);
		Assert.assertNotNull(pipv2.getParticipants());
		Assert.assertEquals(pipv2.getParticipants().size(), 0);
		
		// TODO- test messing with the participants list
	}
	
	@Test
	public void testSix() throws Exception {

		CreateActivityView req = new CreateActivityView ();
		
		ActivityController ac = SingletonShim.getBean(ActivityController.class);
		MailManagerMock mmm = (MailManagerMock)DartObjectFactory.getInstance().getMailManager();
		mmm.clearCaptureList();

		req.setType(Request.DATA_ACCESS);
		req.setOfficialName("official name");
		
		Object obj = ac.createActivity(req);
		Assert.assertNotNull(obj);
		Assert.assertTrue(obj instanceof NewActivityView);
		
		NewActivityView nav = (NewActivityView)obj;
		Assert.assertTrue(nav.getActivityId() > 0);
		Assert.assertTrue(nav.getRequestId() > 0);
		
		DartRequest dr = DartRequest.findById(nav.getRequestId());
		Assert.assertNotNull(dr);
		Assert.assertEquals(dr.getActivity().getId(), nav.getActivityId());
		
		// did I get an email when the request was created?
		int counter = 0;
		for (MimeMessage mm : mmm.getMessages()) {
			if (mm.getSubject().contains(dr.getTrackingNumber())) {
				counter++;
			}
		}

		Assert.assertTrue(counter > 0);
	}
}
