using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using sodoff.Attributes;
using sodoff.Model;
using sodoff.Schema;
using sodoff.Util;
using GroupMember = sodoff.Model.GroupMember;

namespace sodoff.Controllers.Common;

public class GroupController : Controller {
    // Any permission that is commented out is not implemented.
    private static readonly List<string> PermissionsMember = [
        //"Delete Own Msg",
        //"Post Message"
    ];
    private static readonly List<string> PermissionsElder = [
        //"Invite",
        "Approve Join Request",
        //"Post News",
        //"Delete Own Msg",
        //"Delete Any Msg",
        //"Delete News",
        //"Post Message",
        "Remove Member"
    ];
    private static readonly List<string> PermissionsLeader = [
        //"Invite",
        "Approve Join Request",
        "Assign Leader",
        "Assign Elder",
        "Demote Elder",
        "Edit Group",
        //"Post News",
        //"Delete Own Msg",
        //"Delete Any Msg",
        //"Delete News",
        //"Post Message",
        "Remove Member"
    ];
    
    private static readonly List<RolePermission> RolePermissions = [
        new RolePermission {
            GroupType = GroupType.Public,
            Role = UserRole.Member,
            Permissions = PermissionsMember
        }, new RolePermission {
            GroupType = GroupType.Public,
            Role = UserRole.Elder,
            Permissions = PermissionsElder
        }, new RolePermission {
            GroupType = GroupType.Public,
            Role = UserRole.Leader,
            Permissions = PermissionsLeader
        },
        
        new RolePermission {
            GroupType = GroupType.MembersOnly,
            Role = UserRole.Member,
            Permissions = PermissionsMember
        }, new RolePermission {
            GroupType = GroupType.MembersOnly,
            Role = UserRole.Elder,
            Permissions = PermissionsElder
        }, new RolePermission {
            GroupType = GroupType.MembersOnly,
            Role = UserRole.Leader,
            Permissions = PermissionsLeader
        },
        
        new RolePermission {
            GroupType = GroupType.Private,
            Role = UserRole.Member,
            Permissions = PermissionsMember
        }, new RolePermission {
            GroupType = GroupType.Private,
            Role = UserRole.Elder,
            Permissions = PermissionsElder
        }, new RolePermission {
            GroupType = GroupType.Private,
            Role = UserRole.Leader,
            Permissions = PermissionsLeader
        }
    ];

    private readonly DBContext ctx;

    public GroupController(DBContext ctx) {
        this.ctx = ctx;
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/CreateGroup")]
    [VikingSession]
    public IActionResult CreateGroup(Viking viking, [FromForm] string apiKey, [FromForm] string groupCreateRequest) {
        uint gameId = ClientVersion.GetGameID(apiKey);

        if (viking.GroupMembership != null)
            return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.CreatorIsNotApproved });

        CreateGroupRequest request = XmlUtil.DeserializeXml<CreateGroupRequest>(groupCreateRequest);
        request.Name = request.Name.Trim();

        // Cue the gauntlet of validity checks.
        if (request.Type <= GroupType.System)
            return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupTypeIsInvalid });
        //if (request.MaxMemberLimit < 4) return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupMaxMemberLimitInvalid }); // Not actually used by the game.
        if (request.Name.Length == 0)
            return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupNameIsEmpty });
        if (request.Description.Length == 0)
            return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupDescriptionIsEmpty });
        if (ctx.Groups.Any(g => g.Name.ToLower() == request.Name.ToLower()))
            return Ok(new CreateGroupResult { Success = false, Status = CreateGroupStatus.GroupNameIsDuplicate });

        Model.Group group = new Model.Group {
            Name = request.Name,
            Description = request.Description,
            Logo = request.Logo,
            Color = request.Color,
            Type = request.Type,
            CreateDate = DateTime.UtcNow,
            GameID = gameId,
            MaxMemberLimit = request.MaxMemberLimit ?? 50,
            GroupID = Guid.NewGuid(),
            Vikings = new List<GroupMember>()
        };

        ctx.Groups.Add(group);
        group.Vikings.Add(new GroupMember {
            Viking = viking,
            Group = group,
            UserRole = UserRole.Leader,
            JoinDate = group.CreateDate
        });
        group.LastActiveTime = group.CreateDate;
        ctx.SaveChanges();

        return Ok(new CreateGroupResult {
            Success = true,
            Status = CreateGroupStatus.Success,
            Group = new Schema.Group {
                Name = group.Name,
                Description = group.Description,
                Logo = group.Logo,
                Color = group.Color,
                Type = group.Type,
                OwnerID = viking.Uid.ToString(),
                Points = 0,//group.Points,
                Active = false,//group.Vikings.Count >= 4,
                MemberLimit = group.MaxMemberLimit,
                GroupID = group.GroupID.ToString()
            }
            // TODO: Delete after 15 days of less than 4 members.
        });
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/EditGroup")]
    [VikingSession]
    public IActionResult EditGroup(Viking viking, [FromForm] string apiKey, [FromForm] string groupEditRequest) {
        EditGroupRequest request = XmlUtil.DeserializeXml<EditGroupRequest>(groupEditRequest);
        request.Name = request.Name.Trim();

        GroupMember? vikingRole = viking.GroupMembership;
        if (vikingRole == null || vikingRole.Group.GroupID.ToString() != request.GroupID)
            return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.GroupNotFound });
        if (vikingRole.UserRole < UserRole.Elder)
            return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.PermissionDenied });

        // Cue the gauntlet of validity checks.
        if (request.Type != null && request.Type <= GroupType.System)
            return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.GroupTypeIsInvalid });
        //if (request.MaxMemberLimit < 4) return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.GroupMaxMemberLimitInvalid }); // Not actually used by the game.
        if (string.IsNullOrEmpty(request.Name))
            request.Name = vikingRole.Group.Name;
        if (string.IsNullOrEmpty(request.Description))
            request.Description = vikingRole.Group.Description;
        if (request.Name != vikingRole.Group.Name && ctx.Groups.Any(g => g.Name.ToLower() == request.Name.ToLower()))
            return Ok(new EditGroupResult { Success = false, Status = EditGroupStatus.GroupNameIsDuplicate });
        
        vikingRole.Group.Name = request.Name;
        vikingRole.Group.Description = request.Description;
        if (request.Type != null)
            vikingRole.Group.Type = (GroupType)request.Type;
        if (!string.IsNullOrEmpty(request.Color))
            vikingRole.Group.Color = request.Color;
        if (!string.IsNullOrEmpty(request.Logo))
            vikingRole.Group.Logo = request.Logo;
        if (request.MaxMemberLimit != null)
            vikingRole.Group.MaxMemberLimit = (int)request.MaxMemberLimit;

        ctx.SaveChanges();

        return Ok(new EditGroupResult {
            Success = true,
            Status = EditGroupStatus.Success,
            NewRolePermissions = RolePermissions
        });
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("GroupWebService.asmx/JoinGroup")]
    [VikingSession]
    public IActionResult JoinGroupV1(Viking viking, [FromForm] string apiKey, [FromForm] string groupID) {
        Guid parsedGroupID = Guid.Parse(groupID);
        uint gameId = ClientVersion.GetGameID(apiKey);
        
        // Check for loyalty.
        if (viking.GroupMembership != null)
            return Ok(new JoinGroupResult { GroupStatus = GroupMembershipStatus.SELF_BLOCKED });

        Model.Group? group = ctx.Groups.FirstOrDefault(g => g.GroupID == parsedGroupID);
        if (group != null) {
            // This check is only on this side to prevent people from attempting to circumvent the join limit.
            if (group.Type <= GroupType.System || group.Vikings.Count < group.MaxMemberLimit) {
                group.Vikings.Add(new GroupMember {
                    Viking = viking,
                    Group = group,
                    UserRole = UserRole.Member
                });
                ctx.SaveChanges();
                return Ok(new JoinGroupResult { GroupStatus = GroupMembershipStatus.APPROVED });
            }
        }
        return Ok(new JoinGroupResult { GroupStatus = GroupMembershipStatus.REJECTED });
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/JoinGroup")]
    [VikingSession]
    public IActionResult JoinGroup(Viking viking, [FromForm] string apiKey, [FromForm] string groupJoinRequest) {
        uint gameId = ClientVersion.GetGameID(apiKey);

        JoinGroupRequest request = XmlUtil.DeserializeXml<JoinGroupRequest>(groupJoinRequest);
        Guid parsedGroupID = Guid.Parse(request.GroupID);
        Model.Group? group = ctx.Groups.FirstOrDefault(g => g.GroupID == parsedGroupID);
        if (group == null) return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.Error });
        if (group.Type >= GroupType.Private) {
            return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.GroupTypeIsNotPublic });
        }
        
        GroupMember? existing = viking.GroupMembership;
        if (existing != null) {
            if (existing.Group == group)
                return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.UserAlreadyMemberOfTheGroup });
            
            existing.Group.Vikings.Remove(existing);
            if (!existing.Group.Vikings.Any()) ctx.Groups.Remove(existing.Group);
        }
        
        if (group.Type == GroupType.MembersOnly) {
            if (!group.JoinRequests.Any(r => r.Viking == viking))
                group.JoinRequests.Add(new GroupJoinRequest {
                    Group = group,
                    Viking = viking,
                    Message = request.Message
                });
            ctx.SaveChanges();
            return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.JoinRequestPending });
        }

        if (group.Vikings.Count >= group.MaxMemberLimit) 
            return Ok(new GroupJoinResult { Success = false, Status = JoinGroupStatus.GroupIsFull });
        
        GroupMember joinee = new GroupMember {
            Viking = viking,
            Group = group,
            UserRole = UserRole.Member,
            JoinDate = DateTime.UtcNow
        };
        group.Vikings.Add(joinee);
        group.LastActiveTime = joinee.JoinDate;
        ctx.SaveChanges();
        return Ok(new GroupJoinResult { Success = true, Status = JoinGroupStatus.Success });
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/LeaveGroup")]
    [VikingSession]
    public IActionResult LeaveGroup(Viking viking, [FromForm] string groupLeaveRequest) {
        LeaveGroupRequest request = XmlUtil.DeserializeXml<LeaveGroupRequest>(groupLeaveRequest);
        GroupMember? vikingRole = viking.GroupMembership;
        if (vikingRole == null || vikingRole.Group.GroupID.ToString() != request.GroupID)
            return Ok(new LeaveGroupResult { Success = false, Status = LeaveGroupStatus.Error });
        GroupMember? targetRole;
        if (viking.Uid == Guid.Parse(request.UserID)) {
            targetRole = vikingRole.Group.Vikings.FirstOrDefault(gv => gv.Viking == viking);
        } else if (vikingRole.UserRole >= UserRole.Elder) {
            targetRole = vikingRole.Group.Vikings.FirstOrDefault(gv => gv.Viking.Uid == Guid.Parse(request.UserID));
        } else return Ok(new LeaveGroupResult { Success = false, Status = LeaveGroupStatus.Error });

        if (targetRole == null)
            return Ok(new LeaveGroupResult { Success = false, Status = LeaveGroupStatus.UserNotAMemberOfTheGroup });
        vikingRole.Group.Vikings.Remove(targetRole);
        if (!vikingRole.Group.Vikings.Any()) ctx.Groups.Remove(vikingRole.Group);
        ctx.SaveChanges();
        return Ok(new LeaveGroupResult { Success = true, Status = LeaveGroupStatus.Success });
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/GetGroups")]
    public IActionResult GetGroups([FromForm] string apiKey, [FromForm] string getGroupsRequest) {
        uint gameId = ClientVersion.GetGameID(apiKey);
        GetGroupsRequest request = XmlUtil.DeserializeXml<GetGroupsRequest>(getGroupsRequest);

        IQueryable<Model.Group> groupsQuery = ctx.Groups.Where(g => g.GameID == gameId);
        if (request.ForUserID != null) {
            Viking? target = ctx.Vikings.FirstOrDefault(v => Guid.Parse(request.ForUserID) == v.Uid);
            if (target == null) return Ok(new GetGroupsResult { Success = false });
            if (target.GroupMembership?.Group == null) return Ok();
            groupsQuery = groupsQuery.Where(g => g.GroupID == target.GroupMembership.Group.GroupID);
        }

        if (request.Name != null)
            groupsQuery = groupsQuery.Where(g => g.Name.ToLower().Contains(request.Name.ToLower()));

        groupsQuery = groupsQuery.OrderByDescending(g => g.Points).ThenBy(g => g.Id);
        int skip = 0;
        if (request.PageSize != null) {
            if ((request.PageNo ?? 0) > 1)
                skip = (int)((request.PageNo! - 1) * request.PageSize);
            if (skip > 0)
                groupsQuery = groupsQuery.Skip(skip);
            groupsQuery = groupsQuery.Take((int) request.PageSize);
        }

        if (request.IncludeMemberCount)
            groupsQuery = groupsQuery.Include(g => g.Vikings);

        var groups = groupsQuery.ToList();
        return Ok(new GetGroupsResult {
            Success = true,
            Groups = groups.Select((g, i) => {
                Schema.Group group = new Schema.Group {
                    Name = g.Name,
                    Description = g.Description,
                    GroupID = g.GroupID.ToString(),
                    OwnerID = (g.Vikings.FirstOrDefault(v => v.UserRole == UserRole.Leader)?.Viking?.Uid ?? Guid.Empty).ToString(),
                    Color = g.Color,
                    Logo = g.Logo,
                    Type = g.Type,
                    Rank = i+skip+1,
                    Points = g.Points,
                    MemberLimit = g.MaxMemberLimit
                };
                if (request.IncludeMemberCount) group.TotalMemberCount = g.Vikings.Count;
                return group;
            }).ToArray(),
            RolePermissions = RolePermissions
        });
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/RemoveMember")]
    [VikingSession]
    public IActionResult RemoveMember(Viking viking, [FromForm] string removeMemberRequest) {
        RemoveMemberRequest request = XmlUtil.DeserializeXml<RemoveMemberRequest>(removeMemberRequest);
        GroupMember? vikingRole = viking.GroupMembership;
        if (vikingRole == null || vikingRole.Group.GroupID != Guid.Parse(request.GroupID))
            return Ok(new RemoveMemberResult { Success = false, Status = RemoveMemberStatus.Error });
        
        if (vikingRole.UserRole < UserRole.Elder)
            return Ok(new RemoveMemberResult { Success = false, Status = RemoveMemberStatus.UserHasNoPermission });
        
        GroupMember? targetRole = vikingRole.Group.Vikings.FirstOrDefault(gv => gv.Viking.Uid == Guid.Parse(request.RemoveUserID));
        if (targetRole == null)
            return Ok(new RemoveMemberResult { Success = false, Status = RemoveMemberStatus.UserNotAMemberOfTheGroup });

        if (targetRole.UserRole >= vikingRole.UserRole)
            return Ok(new RemoveMemberResult { Success = false, Status = RemoveMemberStatus.InvalidParameters });

        vikingRole.Group.Vikings.Remove(targetRole);
        if (!vikingRole.Group.Vikings.Any())
            ctx.Groups.Remove(vikingRole.Group);
        ctx.SaveChanges();
        return Ok(new RemoveMemberResult { Success = true, Status = RemoveMemberStatus.Success });
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/AuthorizeJoinRequest")]
    [VikingSession]
    public IActionResult AuthorizeJoinRequest(Viking viking, [FromForm] string apiKey, [FromForm] string authorizeJoinRequest) {
        uint gameId = ClientVersion.GetGameID(apiKey);

        AuthorizeJoinRequest request = XmlUtil.DeserializeXml<AuthorizeJoinRequest>(authorizeJoinRequest);
        GroupMember? vikingRole = viking.GroupMembership;
        if (vikingRole == null || vikingRole.Group.GroupID != Guid.Parse(request.GroupID))
            return Ok(new AuthorizeJoinResult { Success = false, Status = AuthorizeJoinStatus.ApproverNotInThisGroup });
        
        if (vikingRole.UserRole < UserRole.Elder)
            return Ok(new AuthorizeJoinResult { Success = false, Status = AuthorizeJoinStatus.ApproverHasNoPermission });
        
        Viking? target = ctx.Vikings.FirstOrDefault(v => v.Uid == Guid.Parse(request.JoineeID));
        if (target == null)
            return Ok(new AuthorizeJoinResult { Success = false, Status = AuthorizeJoinStatus.Error });

        GroupMember? existing = target.GroupMembership;
        if (existing != null) {
            return Ok(new AuthorizeJoinResult {
                Success = false,
                Status = existing.Group == vikingRole.Group
                    ? AuthorizeJoinStatus.UserAlreadyMemberOfTheGroup
                    : AuthorizeJoinStatus.UserHasNoJoinRequest
            });
        }

        if (vikingRole.Group.Vikings.Count >= vikingRole.Group.MaxMemberLimit)
            return Ok(new AuthorizeJoinResult { Success = false, Status = AuthorizeJoinStatus.GroupIsFull });
        
        if (request.Approved) {
            GroupMember joinee = new GroupMember {
                Viking = target,
                Group = vikingRole.Group,
                UserRole = UserRole.Member,
                JoinDate = DateTime.UtcNow
            };
            vikingRole.Group.Vikings.Add(joinee);
            vikingRole.Group.LastActiveTime = joinee.JoinDate;
        }

        GroupJoinRequest? joinRequest = ctx.GroupJoinRequests.Find(target.Id, vikingRole.GroupID);
        if (joinRequest != null)
            ctx.GroupJoinRequests.Remove(joinRequest);
        ctx.SaveChanges();
        return Ok(new AuthorizeJoinResult { Success = true, Status = AuthorizeJoinStatus.Success });

    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/AssignRole")]
    [VikingSession]
    public IActionResult AssignRole(Viking viking, [FromForm] string assignRoleRequest) {
        AssignRoleRequest request = XmlUtil.DeserializeXml<AssignRoleRequest>(assignRoleRequest);
        GroupMember? vikingRole = viking.GroupMembership;
        if (vikingRole == null || vikingRole.Group.GroupID != Guid.Parse(request.GroupID))
            return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.ApproverNotMemberOfTheGroup });
        
        if (vikingRole.UserRole < UserRole.Elder) 
            return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.ApproverHasNoPermission });
        
        GroupMember? targetRole = vikingRole.Group.Vikings.FirstOrDefault(gv => gv.Viking.Uid == Guid.Parse(request.MemberID));
        if (targetRole == null)
            return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.MemberNotPartOfTheGroup });

        if (targetRole.UserRole == request.NewRole)
            return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.MemberAlreadyInTheRole });
        
        if (vikingRole.UserRole == UserRole.Leader) {
            // Disallow leader from simply demoting themself.
            if (viking == targetRole.Viking)
                return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.ApproverHasNoPermission });
        } else if (viking != targetRole.Viking || request.NewRole > vikingRole.UserRole) {
            // Disallow Elders from promoting themselves to leader, or promoting anyone else to elder, but allow them to demote themselves.
            return Ok(new AssignRoleResult { Success = false, Status = AssignRoleStatus.ApproverHasNoPermission });
        }
            
        targetRole.UserRole = request.NewRole;
        if (request.NewRole == UserRole.Leader)
            vikingRole.UserRole = UserRole.Elder; // This is the only way a leader can demote themself.

        ctx.SaveChanges();
        return Ok(new AssignRoleResult { Success = true, Status = AssignRoleStatus.Success });
        
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("V2/GroupWebService.asmx/GetPendingJoinRequest")]
    [VikingSession]
    public IActionResult GetPendingJoinRequests(Viking viking, [FromForm] string getPendingJoinRequest) {
        GetPendingJoinRequest request = XmlUtil.DeserializeXml<GetPendingJoinRequest>(getPendingJoinRequest);
        GroupMember? vikingRole = viking.GroupMembership;
        if (vikingRole?.Group.GroupID == Guid.Parse(request.GroupID) && vikingRole?.UserRole >= UserRole.Elder) {
            return Ok(new GetPendingJoinResult {
                Success = true,
                Requests = vikingRole.Group.JoinRequests
                    .Select(r => {
                        PendingJoinRequest req = new PendingJoinRequest {
                            UserID = r.Viking.Uid.ToString(),
                            GroupID = vikingRole.Group.GroupID.ToString(),
                            StatusID = GroupJoinRequestStatus.Pending,
                            Message = r.Message ?? "Hello! Please invite me to your Clan!"
                        };
                        req.FromUserID = req.UserID;
                        return req;
                    }).ToArray()
            });
        }
        return Ok(new GetPendingJoinResult { Success = false });
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("GroupWebService.asmx/GetGroupsByUserID")]
    public Schema.Group[] GetGroupsByUserID([FromForm] string apiKey, [FromForm] Guid userId) {
        uint gameId = ClientVersion.GetGameID(apiKey);

        Viking? viking = ctx.Vikings.FirstOrDefault(v => v.Uid == userId);
        if (viking == null) return [];

        Model.Group? group = viking.GroupMembership.Group;
        return [
            new Schema.Group {
                GroupID = group.GroupID.ToString(),
                Name = group.Name,
                Color = group.Color,
                Logo = group.Logo,
                MemberLimit = group.MaxMemberLimit
            }
        ];
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("GroupWebService.asmx/GetGroupsByGroupType")]
    public Schema.Group[] GetGroupsByGroupType([FromForm] string apiKey, [FromForm] string groupType) {
        uint gameId = ClientVersion.GetGameID(apiKey);
        
        List<Schema.Group> groups = new List<Schema.Group>();
        foreach (Model.Group group in ctx.Groups) {
            if (group.GameID == gameId && group.Type.ToString() == groupType) groups.Add(new Schema.Group {
                GroupID = group.GroupID.ToString(),
                Name = group.Name,
                Color = group.Color,
                Logo = group.Logo,
                Type = group.Type,
                MemberLimit = group.MaxMemberLimit
            });
        }
        return groups.ToArray();
    }

    [HttpPost]
    [Produces("application/xml")]
    [Route("GroupWebService.asmx/GetMembersByGroupID")]
    public Schema.GroupMember[] GetMembersByGroupID([FromForm] string groupID) {
        Guid parsedGroupID = Guid.Parse(groupID);
        Model.Group? group = ctx.Groups.FirstOrDefault(
            g => g.GroupID == parsedGroupID
        );
        if (group == null) return [];

        return group.Vikings.Select(v => new Schema.GroupMember {
            DisplayName = group.GameID == ClientVersion.MB && v.Viking.AvatarSerialized != null
                ? XmlUtil.DeserializeXml<AvatarData>(v.Viking.AvatarSerialized).DisplayName
                : v.Viking.Name,
            UserID = v.Viking.Uid.ToString(),
            JoinDate = v.JoinDate,
            RoleID = (int) v.UserRole,
            Online = false, // There's no way to check this.
            Rank = 0,
            GroupID = group.GroupID.ToString(),
            Points = group.Points
        }).ToArray();
    }
}
