package samuelb.capripol;

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import javax.persistence.*;
import java.util.*;

/*
Entity Representing groups in the system
Holds a set of group members, roles and a framework.
 */

@Table(name="FocusGroups")
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
        property = "groupID")
public class Group {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long groupID;

    private String groupName;

    @ManyToMany
    @JoinTable(name = "GroupMembers",
            joinColumns = @JoinColumn(
                    name = "groupID"),
            inverseJoinColumns = @JoinColumn(
                    name = "userID"))
    private Set<User> groupMembers = new HashSet<>();

    @OneToMany(mappedBy = "group", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<GroupUserRoles> groupUserRoles = new HashSet<>();

    @ManyToOne(fetch = FetchType.EAGER, optional = true)
    @JoinColumn(name="frameworkID", nullable = true)
    private Framework framework;

    public Group(){}

    public Group(String groupName, Set<User> groupMembers, Framework framework) {
        this.groupName = groupName;
        this.groupMembers = groupMembers;
        this.framework = framework;
    }

    public Long getGroupID() {
        return groupID;
    }

    public void setGroupID(Long groupID) {
        this.groupID = groupID;
    }

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Set<User> getGroupMembers() {
        return groupMembers;
    }

    public void setGroupMembers(Set<User> groupMembers) {
        this.groupMembers = groupMembers;
    }

    public void addMembers(Set<User> groupMembers){
        this.groupMembers.addAll(groupMembers);
    }

    public void addMember(User groupMember){
        this.groupMembers.add(groupMember);
    }

    public Set<GroupUserRoles> getGroupUserRoles() {
        return groupUserRoles;
    }

    public void setGroupUserRoles(Set<GroupUserRoles> groupUserRoles) {
        if(this. groupUserRoles == null){
            this.groupUserRoles = groupUserRoles;
        }else{
            this.groupUserRoles.retainAll(groupUserRoles);
            this.groupUserRoles.addAll(groupUserRoles);
        }
    }

    public String groupMembersToString(){
        String out = "";
        Map<String, List<String>> roleUsers = new HashMap<>();
        Set<GroupRole> groupRoles = new HashSet<>();
        if(groupMembers.size() > 0){
            for(GroupUserRoles groupUserRoles: groupUserRoles){
                roleUsers.computeIfAbsent(groupUserRoles.getGroupRole().getName(), k-> new ArrayList<>()).add(groupUserRoles.getUser().getUsername());
            }
            int roleCount = 0;
            for(Map.Entry<String, List<String>> entry: roleUsers.entrySet()){
                String role = entry.getKey();
                List<String> users = entry.getValue();
                if(roleCount >= 1){
                    out+=", ";
                }
                roleCount++;
                out += role +"(s): ";
                int count = 0;
                for(String user: users){
                    if(count >= 1){
                        out+= ", ";
                    }
                    out += user;
                    count++;
                }
            }
        }else{
            out = "No members";
        }
        return out;
    }

    public boolean hasMember(String groupMemberName) {
        for (User member : this.groupMembers) {
            if (member.getUsername().equals(groupMemberName)) {
                return true;
            }
        }
        return false;
    }

    public User getGroupMember(String groupMemberName){
        for(User member: this.groupMembers){
            if(member.getUsername().equals(groupMemberName)){
                return member;
            }
        }
        return null;
    }

    public Framework getFramework() {
        return framework;
    }

    public void setFramework(Framework framework) {
        this.framework = framework;
    }
}
