import React, {useCallback, useEffect, useState} from 'react';
import {ActivityIndicator, Alert, Pressable, ScrollView, StyleSheet, Text, View} from 'react-native';
import Screen from '../layout/Screen';
import Card from '../UI/Card';
import {Button} from '../UI/Button';
import useGameHook from '../../hooks/useGameHook';
import {getSession} from '../../hooks/SessionStore';
const PlayersScreen = ({navigation, route}) => {
// Initialisation ------------
const session = getSession();
const {getTeams, getTeamMembers, getGroupMembers, removeMember, resetPlayerProgress, getUser, getAdminWaitlist, approveAdmin, rejectAdmin, getSubgroups} = useGameHook();
const isBusiness = Boolean(session.isBusiness);
const isAdmin = Boolean(session.isAcceptedAdmin);
const selectedDepartment = route?.params?.department || null;
// State ----------------------
const [loading, setLoading] = useState(true);
const [players, setPlayers] = useState([]);
const [departmentList, setDepartmentList] = useState([]);
// Handlers -------------------
const loadData = useCallback(async () => {
if (!session.currentGid) { setLoading(false); return; }
const effectiveSGid = isBusiness
? ((isAdmin && selectedDepartment?.SGid) ? selectedDepartment.SGid : (isAdmin ? null : session.currentSGid))
: null;
if (isBusiness && isAdmin && !selectedDepartment) {
const sgs = await getSubgroups(session.currentGid);
setDepartmentList((sgs || []).filter((sg) => !sg.IsAdminGroup));
setPlayers([]);
setLoading(false);
return;
}
// Load subgroup names for department display (business accounts)
let subgroupNameMap = {};
if (isBusiness) {
const sgs = await getSubgroups(session.currentGid);
for (const sg of (sgs || [])) {
if (!sg.IsAdminGroup) subgroupNameMap[sg.SGid] = sg.SubGroupName;
}
}
// Get ALL members (including admins)
const allMembers = await getGroupMembers(session.currentGid, effectiveSGid ?? null);
// Get admin waitlist entries
const waitlist = effectiveSGid ? [] : await getAdminWaitlist(session.currentGid);
// Deduplicate allMembers by Uid — a user may have two rows if they were a
// regular member before being approved as an admin. Prefer the admin row.
const seenUids = new Set();
const uniqueMembers = (allMembers || [])
.sort((a, b) => (b.IsAcceptedAdmin ? 1 : 0) - (a.IsAcceptedAdmin ? 1 : 0))
.filter((m) => { if (seenUids.has(m.Uid)) return false; seenUids.add(m.Uid); return true; });
// Build team lookup: { Uid -> { teamCode, teamName, isLeader } }
const allTeams = await getTeams(session.currentGid, effectiveSGid ?? null);
const teamInfoByUid = {};
for (const team of (allTeams || [])) {
const tms = await getTeamMembers(team.Tid);
for (const tm of (tms || [])) {
teamInfoByUid[tm.Uid] = {
teamCode: team.JoinCode,
teamName: team.TeamName,
isLeader: Boolean(tm.IsLeader),
};
}
}
// Build player list — include admins with tags
const playerList = [];
for (const m of uniqueMembers) {
// Skip the current admin viewing the list
if (m.Uid === session.currentUid) continue;
const user = await getUser(m.Uid);
if (user) {
// A group member may also be on the admin waitlist (applied after joining as a player).
// Check the waitlist first so they are treated as pending, not a regular player.
const waitlistEntry = (waitlist || []).find((w) => w.Uid === m.Uid);
let adminTag = null;
let waitlistId = null;
if (waitlistEntry) {
adminTag = '[Admin Awaiting Response]';
waitlistId = waitlistEntry.id;
} else if (m.IsAcceptedAdmin) {
adminTag = '[ADMIN]';
}
playerList.push({
...user,
membershipId: m.id,
team: teamInfoByUid[m.Uid] || null,
adminTag,
waitlistId,
departmentName: subgroupNameMap[m.SGid] || null,
});
}
}
// Include waitlisted users who are not yet group members at all
for (const w of (waitlist || [])) {
if (playerList.some((p) => p.Uid === w.Uid)) continue;
if (w.Uid === session.currentUid) continue;
const user = await getUser(w.Uid);
if (user) {
playerList.push({
...user,
membershipId: null,
team: null,
adminTag: '[Admin Awaiting Response]',
waitlistId: w.id,
departmentName: null,
});
}
}
setPlayers(playerList);
setLoading(false);
}, [session.currentGid, session.currentUid, session.currentSGid, isBusiness, isAdmin, selectedDepartment, selectedDepartment?.SGid]);
useEffect(() => { loadData(); }, [loadData]);
const handleRemovePlayer = async (membershipId) => {
await removeMember(membershipId);
await loadData();
};
const handleResetPlayerProgress = (player) => {
Alert.alert(
'Reset Progress',
`Reset all cache claims for ${player.username}?`,
[
{text: 'Cancel', style: 'cancel'},
{
text: 'Reset',
style: 'destructive',
onPress: async () => {
await resetPlayerProgress(session.currentGid, player.Uid);
Alert.alert('Done', `Progress for ${player.username} has been reset.`);
},
},
],
);
};
// Approve a waitlisted admin and refresh the list
const handleApproveAdmin = async (player) => {
await approveAdmin(player.waitlistId);
await loadData();
};
// Deny (remove from waitlist) a pending admin and refresh the list
const handleDenyAdmin = async (player) => {
await rejectAdmin(player.waitlistId);
await loadData();
};
// View -----------------------
if (loading) {
return (
);
}
if (!session.currentGid) {
return (
Create or join a game first.
);
}
if (isBusiness && isAdmin && !selectedDepartment) {
return (
Departments
{departmentList.map((department) => (
navigation.navigate('PlayersScreen', {department})}
>
{department.SubGroupName}
Open
))}
{departmentList.length === 0 && (
No departments yet.
)}
);
}
return (
Players
{players.map((player) => (
// Waitlisted admins get a light red tint so they stand out from regular players
{player.username}
{player.adminTag && (
{' '}{player.adminTag}
)}
{/* Show department name in brackets for non-admin players (org accounts) */}
{!player.adminTag && player.departmentName && (
{' '}({player.departmentName})
)}
{player.team?.isLeader && (
(Team Leader)
)}
{player.team && (
{player.team.teamCode}
)}
{/* Waitlisted admins get Approve / Deny instead of the normal player actions */}
{player.waitlistId ? (
<>
))}
{players.length === 0 && (
No players have joined yet.
)}
);
};
const styles = StyleSheet.create({
center: {justifyContent: 'center', alignItems: 'center', flex: 1},
container: {padding: 0},
body: {color: '#4b5563', fontSize: 15},
sectionTitle: {
fontSize: 20,
fontWeight: '700',
color: '#1f2937',
marginBottom: 12,
paddingHorizontal: 15,
paddingTop: 15,
},
openLabel: {fontSize: 13, fontWeight: '700', color: '#2563eb'},
listSection: {flex: 1, paddingHorizontal: 15},
emptyText: {color: '#9ca3af', textAlign: 'center', marginTop: 30, fontSize: 14},
playerRow: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
marginBottom: 8,
},
playerName: {fontSize: 15, fontWeight: '600', color: '#1f2937', flex: 1},
playerMeta: {flexDirection: 'row', alignItems: 'center', gap: 6},
leaderBadge: {fontSize: 11, color: '#2563eb', fontWeight: '700'},
teamCodeBadge: {fontSize: 12, fontWeight: '700', color: '#16a34a', letterSpacing: 1},
adminBadge: {fontSize: 12, fontWeight: '700', color: '#dc2626'},
waitlistBadge: {fontSize: 11, fontWeight: '600', color: '#f59e0b'},
actionRow: {flexDirection: 'row', gap: 8},
resetButton: {backgroundColor: '#f59e0b', borderColor: '#f59e0b', minHeight: 36, flex: 1, paddingHorizontal: 10},
removeButton: {backgroundColor: '#dc2626', borderColor: '#dc2626', minHeight: 36, flex: 1, paddingHorizontal: 10},
actionLabel: {color: '#ffffff', fontWeight: '600', fontSize: 13},
departmentName: {fontSize: 14, color: '#6b7280', fontStyle: 'italic'},
// Waitlisted admin card tint — light red so they read as pending, not regular players
waitlistCard: {backgroundColor: '#FFD1DC', borderColor: '#fca5a5'},
// Approve / deny buttons for waitlisted admins
approveButton: {backgroundColor: '#16a34a', borderColor: '#16a34a', minHeight: 36, flex: 1, paddingHorizontal: 10},
denyButton: {backgroundColor: '#dc2626', borderColor: '#dc2626', minHeight: 36, flex: 1, paddingHorizontal: 10},
});
export default PlayersScreen;