package samuelb.capripol.Controllers;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import samuelb.capripol.*;
import samuelb.capripol.Repositories.FocusRepository;
import samuelb.capripol.Repositories.SightingRepository;
import samuelb.capripol.Repositories.UserRepository;
import samuelb.capripol.Services.UserDetailsServiceImpl;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.security.Principal;
import java.time.ZonedDateTime;
import java.util.*;
/*
Controller for the Reports Page
 */
@Controller
@SessionAttributes({"userEntity", "focusEntity", "claimEntity"})
public class ReportController {

    @Autowired
    UserRepository userRepository;

    @Autowired
    FocusRepository focusRepository;

    @Autowired
    SightingRepository sightingRepository;

    private static Logger logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);

    //Ensures the current user will always be the first option for the selectpicker in JSP
    @GetMapping("/Reports")
    public ModelAndView reports(Principal principal, Model model){
        List<User> users = userRepository.findAll();
        User user = userRepository.findByUserName(principal.getName());
        users.remove(user);
        users.add(0, user);
        model.addAttribute("users", users);
        return new ModelAndView("Reports");
    }

    /*
    Works as the other datatable data methods. Adds an array of row data + an array of sorting/additional data.
    the 'all' sets are global and used to populate the select pickers. Data for group/frameworks/categories that are specific to
    an individual user or focus is handled by adding them onto the end of the foci/user specific data
     */
    @GetMapping(value = "/ReportData", produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public List<Object> mainMenuData(@RequestParam (required = false) String entitySelected, @RequestParam (required = false) String clicked,
                                     Model model, Principal principal, HttpServletRequest request){
        List<Object> data = new LinkedList<>();
        List<Set<String>> sortDetails = new ArrayList<>();
        Set<String> allGroups = new HashSet<>();
        Set<String> allFrameworks = new HashSet<>();
        Set<String> allCategories = new HashSet<>();
        if(clicked == null || clicked.equals("user")){
            if(entitySelected == null){
                if(!model.containsAttribute("userEntity")){
                    model.addAttribute("userEntity", principal.getName());
                    entitySelected = principal.getName();
                }else{
                    entitySelected = (String)model.getAttribute("userEntity");
                }
            }else{
                model.addAttribute("userEntity", entitySelected);
            }
            User user = userRepository.findByUserName(entitySelected);
            logger.info("Showing results for "+user.getUserName());
            Set<String> allUsers = new HashSet<>();
            List<User> userSet = userRepository.findAll();
            if(user != null){
                List<Focus> foci = focusRepository.findAll();
                for(Focus focus: foci){//loop through each foci the user has access to, add info to data
                    int self = sightingRepository.findSelfClaimsForFocus(user.getUserId(), focus.getFocusId()).size();
                    int peer = sightingRepository.findClaimsForFocusByRelationShipReceived("peer", user.getUserId(), focus.getFocusId()).size();
                    int other = sightingRepository.findClaimsForFocusByRelationShipReceived("other", user.getUserId(), focus.getFocusId()).size();
                    int total = self+peer+other;
                    //groups/frameworks/categories this focus pertains to
                    List<String> groups = new ArrayList<>();
                    List<String> frameworks = new ArrayList<>();
                    List<String> categories = new ArrayList<>();
                    for(Framework framework: focus.getFrameworks()){
                        frameworks.add(framework.getFrameworkName());
                        allFrameworks.add(framework.getFrameworkName());
                        for(Group group: framework.getGroups()){
                            groups.add(group.getGroupName());
                            allGroups.add(group.getGroupName());
                        }
                    }
                    if (!focus.getFocusCategory().equals("")) {
                        categories.add(focus.getFocusCategory());
                        allCategories.add(focus.getFocusCategory());
                    }
                    String[] fociDetails = {focus.getFocusName(), userRepository.getUserRating(user.getRating(focus), user.getUserId(), focus.getFocusId()).toString(),
                            String.valueOf(self), String.valueOf(peer), String.valueOf(other), String.valueOf(total)};
                    List test = Arrays.asList(fociDetails);
                    test = new ArrayList(test);
                    test.add(groups);
                    test.add(frameworks);
                    test.add(categories);
                    data.add(test);
                }
            }
            for(User myUser: userSet){//update user select picker
                allUsers.add(myUser.getUsername());
            }
            sortDetails.add(allUsers);
            Set<String> userSelected = new HashSet<>();
            userSelected.add(user.getUsername());//Get the current user to make them the title and selected option
            sortDetails.add(userSelected);
            sortDetails.add(allGroups);
            sortDetails.add(allFrameworks);
            sortDetails.add(allCategories);
        }else if(clicked.equals("focus")){//same as above but for foci selection
            Focus focus;
            List<Focus> foci = focusRepository.findAll();
            if(entitySelected == null){
                if(!model.containsAttribute("focusEntity")){
                    model.addAttribute("focusEntity", foci.get(0).getFocusName());
                    focus = foci.get(0);
                }else{
                    entitySelected = (String)model.getAttribute("focusEntity");
                }
            }else{
                model.addAttribute("focusEntity", entitySelected);
            }
            List<User> users = userRepository.findAll();
            Set<String> allFoci = new HashSet<>();
            focus = focusRepository.findByFocusName(entitySelected);
            if(focus != null){
                for(User user: users) {
                    String name = user.getUsername();
                    int self = sightingRepository.findSelfClaimsForFocus(user.getUserId(), focus.getFocusId()).size();
                    int peer = sightingRepository.findClaimsForFocusByRelationShip("peer", user.getUserId(), focus.getFocusId()).size();
                    int other = sightingRepository.findClaimsForFocusByRelationShip("other", user.getUserId(), focus.getFocusId()).size();
                    int total = self + peer + other;
                    List<String> groups = new ArrayList<>();
                    List<String> frameworks = new ArrayList<>();
                    List<String> categories = new ArrayList<>();
                    for (Group group : user.getGroups()) {
                        frameworks.add(group.getFramework().getFrameworkName());
                        allFrameworks.add(group.getFramework().getFrameworkName());
                        groups.add(group.getGroupName());
                        allGroups.add(group.getGroupName());
                        String[] userDetails = {user.getUsername(), userRepository.getUserRating(user.getRating(focus), user.getUserId(), focus.getFocusId()).toString(),
                                String.valueOf(self), String.valueOf(peer), String.valueOf(other), String.valueOf(total)};
                        List test = Arrays.asList(userDetails);
                        test = new ArrayList(test);
                        test.add(groups);
                        test.add(frameworks);
                        data.add(test);
                    }
                }
                for(Focus myFocus: foci){
                    allFoci.add(myFocus.getFocusName());
                }
                sortDetails.add(allFoci);
                Set<String> focusSelected = new HashSet<>();
                focusSelected.add(focus.getFocusName());
                sortDetails.add(focusSelected);
                sortDetails.add(allGroups);
                sortDetails.add(allFrameworks);
            }
        }else if(clicked.equals("claim")){
            Set<String> allFoci = new HashSet<>();
            if(entitySelected == null){
                if(!model.containsAttribute("claimEntity")){
                    model.addAttribute("claimEntity", principal.getName());
                    entitySelected = principal.getName();
                }else{
                    entitySelected = (String)model.getAttribute("claimEntity");
                }
            }else{
                model.addAttribute("claimEntity", entitySelected);
            }
            User user = userRepository.findByUserName(entitySelected);
            if(user != null){
                List<Sighting> sightings = sightingRepository.findByUserID(user.getUserId());
                for(Sighting sighting: sightings){
                    String sighterNameAndRating = sighting.getSighter().getUsername() + " - " + sighting.getSighter().getRating(sighting.getFocus()).setScale(2, BigDecimal.ROUND_HALF_EVEN);
                    String[] claimDetails = {sighterNameAndRating, sighting.getFocus().getFocusName(),
                            sighting.getSightee().getUserName(), java.sql.Timestamp.valueOf(sighting.getDateSighted()).toString(), sighting.getSighterSighteeRelationship()};
                    List newList = Arrays.asList(claimDetails);
                    newList = new ArrayList(newList);
                    data.add(newList);
                    allFoci.add(sighting.getFocus().getFocusName());
                }
                Set<String> allUsers = new HashSet<>();
                List<User> userSet = userRepository.findAll();
                for(User myUser: userSet){//update user select picker
                    allUsers.add(myUser.getUsername());
                }
                sortDetails.add(allUsers);
                Set<String> userSelected = new HashSet<>();
                userSelected.add(user.getUsername());//Get the current user to make them the title and selected option
                sortDetails.add(userSelected);
                sortDetails.add(allFoci);
            }
        }
        data.add(sortDetails);
        return data;
    }
}
