package gov.va.vinci.dart;

import gov.va.vinci.dart.biz.Activity;
import gov.va.vinci.dart.biz.Event;
import gov.va.vinci.dart.biz.Group;
import gov.va.vinci.dart.biz.Person;
import gov.va.vinci.dart.biz.Request;
import gov.va.vinci.dart.biz.RequestWorkflow;
import gov.va.vinci.dart.biz.Review;
import gov.va.vinci.dart.biz.Role;
import gov.va.vinci.dart.biz.WorkflowTemplate;
import gov.va.vinci.dart.common.exception.ObjectNotFoundException;
import gov.va.vinci.dart.common.exception.ValidationException;
import gov.va.vinci.dart.common.json.ErrorView;
import gov.va.vinci.dart.db.util.HibernateSessionManager;
import gov.va.vinci.dart.json.ActivityIdView;
import gov.va.vinci.dart.json.EventHistoryView;
import gov.va.vinci.dart.json.EventRequestView;
import gov.va.vinci.dart.json.EventView;
import gov.va.vinci.dart.usr.UserPreferences;
import gov.va.vinci.dart.wf2.WorkflowResolver;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.validation.Valid;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class EventController extends DartController {
	public static final SimpleDateFormat SDF = new SimpleDateFormat("MM/dd/yyyy");
	public static final SimpleDateFormat DATE_TIME_SDF = new SimpleDateFormat("MM/dd/yyyy hh:mm aa");
	private static Log log = LogFactory.getLog(EventController.class);
	
	@RequestMapping(value = "/listEventsByActivity", method = RequestMethod.POST)
	@ResponseBody
	public Object listEventsByActivity(@RequestBody @Valid final ActivityIdView view) {	//ActivityEventView

		log.debug("listEventsByActivity");
		try {
			HibernateSessionManager.start();

			UserPreferences prefs = getUserPreferences();
			Person person = null;
			try {
				person = Person.findById(prefs.getUserId());
			} catch (ObjectNotFoundException e) {
				throw new ObjectNotFoundException("Cannot find person with id: " + prefs.getUserId());
			}
			
			Role.initialize();
			Group.initialize();
			
			
			int activityId = view.getActivityId();
			EventHistoryView result = new EventHistoryView();
			
			Activity activity = null;
			try {
	
				activity = ActivityController.retrieveActivity( activityId );
	
			} catch (ObjectNotFoundException e) {
				log.error("Error loading activity " + activityId, e);
			}

			if( activity != null ) {

				//verify the access permissions
				if( activity.verifyReadAccessPermissions(person) == false ) {
					log.error("Error retrieving events: invalid user permissions.");
					return new ErrorView("Error retrieving events.");
				}
				
				
				ArrayList<Request> requestList = new ArrayList<Request>();
				requestList.addAll(activity.getRequests());

				//there is old SharePoint DART data with bad createdon dates, so retrieve the requests by tracking# instead				
				// sort the list!
				Collections.sort(requestList, Request.getComparator());
				//Collections.sort(requestList, Request.getTrackingNumberComparator());

				
				WorkflowTemplate workflowTemplate = null;
				Group reviewGroup = null;
				if( person.hasRole(Role.REVIEWER) || person.hasRole(Role.READ_ONLY_STAFF) ) {
					for( Group group : person.getGroups() ) {				 
						reviewGroup = group;  // grab the last group the user belongs to?  why?  Because we like it...
					}

				} else if( person.hasRole(Role.NDS_ADMIN) ) {
					workflowTemplate = WorkflowTemplate.findByGroupIdAndWorkflowTypeId(Group.NDS.getId(), WorkflowResolver.WF_NDS);
				}

				
				for (Request req : requestList) {
					
					int reviewId = 0;
					int workflowId = 0;

					
					//
					//for each request in the list, get the workflow and review for this group and role
					
					//Requestor:	reviewId=0, workflowId=0  (ignore anything that came from a task) -> should probably update the task template for the requestor dashboard (always use reviewId=0,workflowId=0)
					//DART Admin: 	reviewId=0, workflowId=0
					//NDS Admin:  	reviewId=0
						//legacy:  workflowId=0
						//new:  workflowId is the NDS workflow if it exists (otherwise workflowId == 0?)
					//Reviewer:
						//legacy:  workflowId=0
						//new:  workflowId is the open workflow for this review group (otherwise workflowId == 0?)
					
					if( person.hasRole(Role.NDS_ADMIN) || 
						person.hasRole(Role.REVIEWER) || person.hasRole(Role.READ_ONLY_STAFF) ) {
						
						if( person.hasRole(Role.NDS_ADMIN) ) {	//NDS Admin

							if( req.getWorkflowTypeId() == WorkflowResolver.WF_RESEARCH_REQUEST || req.getWorkflowTypeId() == WorkflowResolver.WF_PREPARATORY_REQUEST) {	//new request

								//is there an NDS workflow attached to this request?
								if( workflowTemplate != null ) {
									
									RequestWorkflow workflow = RequestWorkflow.findOpenByRequestAndWorkflowTemplateId( req.getId(), workflowTemplate.getId() );	//get the open NDS workflow if there is one
									if( workflow != null ) {
										workflowId = workflow.getId();	//NDS workflow ID
									}//end if

								}//end if -- workflowTemplate

							}//end if -- new NDS request

						} else {	//Reviewer (or Read-only Staff for a Review Group)

							//
							//get the review and the workflow for this group (for each request)
							if( reviewGroup != null ) {

								//step through all of the reviews attached to this request and find all reviews for this group (for any workflow)
								List<Review> reviewsForGroup = Review.listByRequestIdAndGroupId( req.getId(), reviewGroup.getId() );
								if( reviewsForGroup != null ) {

									//if this is a new request, determine if the workflow is open or if it is covered by an open workflow
									for( Review review : reviewsForGroup ) {
										if( review != null ) {
	
											RequestWorkflow reviewWorkflow = review.getWorkflow();
											if( reviewWorkflow != null ) {
	
												if( reviewWorkflow.isClosed() == false ) {
													workflowId = reviewWorkflow.getId();	//review workflow ID
													reviewId = review.getId();
													break;
												}//end if
	
											} else {	//old request, so ignore the workflow
												workflowId = 0;
												reviewId = review.getId();
												break;
											}//end else
	
										}//end if -- review
									}//end for
								}//end if -- reviewsForGroup
							}//end if -- reviewGroup

						}//end else
					}//end if


					result.getRequests().add( populateEventRequestView(req, reviewId, workflowId) );
				}
			}
	
			return result;
		} catch (Exception e) {
			log.error("Error retrieving event data.", e);
			HibernateSessionManager.rollback();
			return new ErrorView("Error retrieving event data.");
		} finally {
			HibernateSessionManager.close();
		}
	}

	@SuppressWarnings({ "unchecked" })
	private EventRequestView populateEventRequestView(final Request request, final int reviewId, final int workflowId) {
		EventRequestView result = new EventRequestView();

		result.setRequestId(request.getId());
		result.setTrackingNumber(request.getTrackingNumber());
		result.setAmendment(request.isAmendment());

		result.setReviewId(reviewId);
		result.setWorkflowId(workflowId);

		
		ArrayList<Event> viewList = new ArrayList<Event>();
		viewList.addAll(request.getEvents());
		
		// sort the list!
		Collections.sort(viewList, Event.getComparator());
		
		for (Event event : viewList) {
			EventView ev = new EventView();
			ev.setDescription(event.getDescription());
			
			String createdBy;
			try {
				createdBy = Person.findByName(event.getCreatedBy()).getFullName();
			} catch (ValidationException e) {
				createdBy = event.getCreatedBy();
			} catch (ObjectNotFoundException e) {
				createdBy = event.getCreatedBy();
			}
			
			ev.setPerson(createdBy);
			ev.setDateTime(DATE_TIME_SDF.format(event.getCreatedOn()));
			result.getEvents().add(ev);
		}

		return result;
	}
}
