package com.controller;

import com.entity.Member;
import com.entity.Project;
import com.entity.Sprint;
import com.entity.Task;
import com.mysql.jdbc.StringUtils;
import com.service.MemberProjectService;
import com.service.ProjectService;
import com.service.SprintsService;
import com.service.TaskService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;

/**
 *
 * Rest controller for the Menu.
 *
 * @author Laurentiu Marcut
 */
@Controller
public class MenuController {

	private static final Logger logger = Logger.getLogger(MenuController.class);

    @Autowired
    private ProjectService projectService;

    @Autowired
    private MemberProjectService memberProjectService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private SprintsService sprintsService;

    /**
     *
     * Projects tab.
     *
     * @param model
     * @return response
     */
	@RequestMapping(value = "/projects", method = RequestMethod.GET)
	public ModelAndView projects(ModelAndView model) {
		model.setViewName("projects");
		return model;
	}

    /**
     *
     * Get all projects.
     *
     * @param currentProject
     * @param model
     * @param request
     * @param response
     * @return response
     */
    @RequestMapping(value = "/projects/getProjects", method = RequestMethod.GET)
    public ModelAndView getProjects(@CookieValue(value = "currentProject", defaultValue = "") String currentProject,
                             ModelAndView model, HttpServletRequest request, HttpServletResponse response) {
        List<Project> projects = new ArrayList<>();
        String member = request.getUserPrincipal().getName();

        try {
            projects = this.projectService.selectAll(member);
            logger.info("Get projects returned: " + projects.size() + " projects for the user " + member);

            boolean isCoockieValid = false;

            for (Project project : projects) {
                if (project.getName().equals(currentProject)) {
                    isCoockieValid = true;
                }
            }

            // Set the loaded project.
            if (!isCoockieValid) {
                Cookie cookie = new Cookie("currentProject", projects.get(0).getName());
                cookie.setPath("/");
                response.addCookie(cookie);
                model.addObject("currentProject", projects.get(0).getName());
            }
        } catch (Exception e) {
            logger.error("Can not get the projects of the user " + member, e);
        }

        model.addObject("projects", projects);
        model.setViewName("projects_list");
        return model;
    }

    /**
     *
     * Members tab.
     *
     * @param model
     * @return response
     */
	@RequestMapping(value = "/members", method = RequestMethod.GET)
	public ModelAndView members(ModelAndView model) {
		model.setViewName("members");
		return model;
	}

    @RequestMapping(value = "/members/getMembers", method = RequestMethod.GET)
    public ModelAndView getMembers(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model) {
        List<Member> members = new ArrayList<>();

        try {
            members = this.memberProjectService.selectAll(project);
        } catch (SQLException e) {
            logger.error("Error in get the members for the project " + project);
        }

        model.addObject("members", members);
        model.setViewName("members_list");
        return model;
    }

    /**
     *
     * Backlog tab.
     *
     * @param project
     * @param model
     * @return response
     */
	@RequestMapping(value = "/backlog", method = RequestMethod.GET)
	public ModelAndView backlog(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model) {
        List<Task> tasks = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            tasks = this.taskService.selectAll(project);
            members = this.memberProjectService.selectAll(project);
        } catch (SQLException e) {
            logger.error("Error in get the backlog tasks for the project " + project);
        }

        logger.info("Project " + project + " returned " + tasks.size() + " tasks.");
        model.addObject("tasks", tasks);
        model.addObject("members", members);
		model.setViewName("backlog");
		return model;
	}

    /**
     *
     * Backlog tasks.
     *
     * @param project
     * @param model
     * @return response
     */
    @RequestMapping(value = "/backlog/tasks", method = RequestMethod.GET)
    public ModelAndView backlogTasks(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model) {
        List<Task> tasks = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            tasks = this.taskService.selectAll(project);
            members = this.memberProjectService.selectAll(project);
        } catch (Exception e) {
            logger.error("Error in get the backlog tasks for the project " + project);
        }

        logger.info("Project " + project + " returned " + tasks.size() + " tasks.");
        model.addObject("tasks", tasks);
        model.addObject("members", members);
        model.setViewName("backlog_tasks");
        return model;
    }

    /**
     *
     * Search in backlog by id.
     *
     * @param project
     * @param model
     * @param id
     * @return response
     */
    @RequestMapping(value = "/backlog/searchById", method = RequestMethod.GET)
    public ModelAndView backlogSearchById(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model,
                                           @RequestParam("searchField") int id) {
        List<Task> tasks = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            Task task = this.taskService.select(id);
            if (!StringUtils.isNullOrEmpty(task.getTitle())) {
                tasks.add(task);
                members = this.memberProjectService.selectAll(project);
            }

        } catch (SQLException e) {
            logger.error("Error in get the backlog tasks for the project " + project);
        }

        logger.info("Project " + project + " returned " + tasks.size() + " tasks.");
        model.addObject("tasks", tasks);
        model.addObject("members", members);
        model.setViewName("backlog_tasks");
        return model;
    }

    /**
     *
     * Search in backlog by tags.
     *
     * @param project
     * @param model
     * @param tags
     * @return response
     */
    @RequestMapping(value = "/backlog/searchByTags", method = RequestMethod.GET)
    public ModelAndView backlogSearchByTags(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model,
                                           @RequestParam("searchField") List<String> tags) {
        List<Task> tasks = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            tasks = this.taskService.selectAllByTags(project, tags);
            members = this.memberProjectService.selectAll(project);
        } catch (SQLException e) {
            logger.error("Error in get the backlog tasks for the project " + project);
        }

        logger.info("Project " + project + " returned " + tasks.size() + " tasks.");
        model.addObject("tasks", tasks);
        model.addObject("members", members);
        model.setViewName("backlog_tasks");
        return model;
    }

    /**
     *
     * Sprints tab.
     *
     * @param model
     * @return response
     */
	@RequestMapping(value = "/sprints", method = RequestMethod.GET)
	public ModelAndView sprints(ModelAndView model) {
		model.setViewName("sprints");
		return model;
	}

    /**
     *
     * Search sprint by id.
     *
     * @param project
     * @param model
     * @param id
     * @return response
     */
    @RequestMapping(value = "/sprints/searchById", method = RequestMethod.GET)
    public ModelAndView getAllSprintsById(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model,
                                          @RequestParam("searchField") int id) {
        List<Sprint> sprints = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            Sprint sprint = this.sprintsService.select(project, id);

            if (sprint.getId() != 0) {
                sprints.add(sprint);
                members = this.memberProjectService.selectAll(project);
            }
        } catch (Exception e) {
            logger.error("Can not get the sprints for the project " + project);
        }

        logger.info("Project " + project + " returned " + sprints.size() + " sprints.");
        model.addObject("sprints", sprints);
        model.addObject("members", members);
        model.setViewName("sprints_tasks");
        return model;
    }

    /**
     *
     * Get all sprints.
     *
     * @param project
     * @param model
     * @return response
     */
    @RequestMapping(value = "/sprints/getAll", method = RequestMethod.GET)
    public ModelAndView getAllSprints(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model) {
        List<Sprint> sprints = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            sprints = this.sprintsService.selectAll(project);
            members = this.memberProjectService.selectAll(project);
        } catch (Exception e) {
            logger.error("Can not get the sprints for the project " + project);
        }

        logger.info("Project " + project + " returned " + sprints.size() + " sprints.");
        model.addObject("sprints", sprints);
        model.addObject("members", members);
        model.setViewName("sprints_tasks");
        return model;
    }

    /**
     *
     * Get sprints tasks.
     *
     * @param project
     * @param model
     * @return response
     */
    @RequestMapping(value = "/sprints/backlogTasks", method = RequestMethod.GET)
    public ModelAndView sprintsBacklogTasks(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model) {
        List<Task> tasks = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            tasks = this.taskService.selectAllWithoutSprint(project);
            members = this.memberProjectService.selectAll(project);
        } catch (Exception e) {
            logger.error("Can not get the backlog tasks for the project " + project + ". ", e);
        }

        logger.info("Project " + project + " returned " + tasks.size() + " tasks.");
        model.addObject("tasks", tasks);
        model.addObject("members", members);
        model.setViewName("backlog_tasks_for_sprints");
        return model;
    }

    /**
     *
     * Search in sprint tasks by id.
     *
     * @param project
     * @param model
     * @param id
     * @return response
     */
    @RequestMapping(value = "/sprints/backlogSearchById", method = RequestMethod.GET)
    public ModelAndView sprintsBacklogSearchById(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model,
                                          @RequestParam("searchField") int id) {
        List<Task> tasks = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            Task task = this.taskService.select(id);
            if (!StringUtils.isNullOrEmpty(task.getTitle()) && !task.getState().equals("Done")) {
                tasks.add(task);
                members = this.memberProjectService.selectAll(project);
            }

        } catch (Exception e) {
            logger.error("Error in get the backlog tasks for the project " + project);
        }

        logger.info("Project " + project + " returned " + tasks.size() + " tasks.");
        model.addObject("tasks", tasks);
        model.addObject("members", members);
        model.setViewName("backlog_tasks_for_sprints");
        return model;
    }

    /**
     *
     * Search in sprint tasks by tags.
     *
     * @param project
     * @param model
     * @param tags
     * @return response
     */
    @RequestMapping(value = "/sprints/backlogSearchByTags", method = RequestMethod.GET)
    public ModelAndView sprintsBacklogSearchByTags(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model,
                                            @RequestParam("searchField") List<String> tags) {
        List<Task> tasks = new ArrayList<>();
        List<Member> members = new ArrayList<>();

        try {
            tasks = this.taskService.selectAllByTags(project, tags);

            for (int i = tasks.size()-1; i >= 0; i--) {
                if (tasks.get(i).getState().equals("Done") || tasks.get(i).getSprint() != 0) {
                    tasks.remove(i);
                }
            }

            members = this.memberProjectService.selectAll(project);
        } catch (Exception e) {
            logger.error("Error in get the backlog tasks for the project " + project);
        }

        logger.info("Project " + project + " returned " + tasks.size() + " tasks.");
        model.addObject("tasks", tasks);
        model.addObject("members", members);
        model.setViewName("backlog_tasks_for_sprints");
        return model;
    }

    /**
     *
     * Statistics tab.
     *
     * @param project
     * @param model
     * @return response
     */
	@RequestMapping(value = "/statistics", method = RequestMethod.GET)
	public ModelAndView statistics(@CookieValue(value = "currentProject", defaultValue = "") String project, ModelAndView model) {
        List<Integer> sprints = new ArrayList<>();

        try {
            sprints = this.sprintsService.selectAllIds(project);
        } catch (Exception e) {
            logger.error("Can not get the sprints for the project " + project + ". ", e);
        }

        logger.info("Project " + project + " returned " + sprints.size() + " sprints.");
        model.addObject("sprints", sprints);
		model.setViewName("statistics");
		return model;
	}

}