import React, { useMemo, useState } from 'react';
import { toast } from '@/components/ds';
import { useWorkerProfiles } from '@/lib/krowHooks';
import { AdminPage } from '@/components/admin/PageShell';
import { UiTreeRenderer } from '@/components/ui-tree/UiTreeRenderer';
import { useUiEditing } from '@/components/ui-tree/UiEditingProvider';
import { UiEditor } from '@/components/ui-editor/UiEditor';
import { composePage } from '@/lib/ui/composition';
import { SORTS } from '@/pages/admin/talent-pool/nodes';
import '@/components/ui-tree/nodeTypes';
import '@/pages/admin/talent-pool/nodes';
/**
* Admin Talent Pool — talent intelligence, not a card gallery.
*/
const BANDS = {
all: () => true,
elite: (s) => s >= 90,
excellent: (s) => s >= 75 && s < 90,
solid: (s) => s >= 60 && s < 75,
building: (s) => s > 0 && s < 60,
unscored: (s) => !s,
};
export default function AdminTalentPool() {
const { data: profiles = [], isLoading } = useWorkerProfiles();
const [search, setSearch] = useState('');
const [skill, setSkill] = useState('all');
const [experience, setExperience] = useState('all');
const [location, setLocation] = useState('all');
const [band, setBand] = useState('all');
const [availability, setAvailability] = useState('all');
const [sort, setSort] = useState('score');
const [saved, setSaved] = useState([]);
const skills = useMemo(
() => [...new Set(profiles.flatMap((p) => p.skills || []))].sort(),
[profiles]
);
const locations = useMemo(
() => [...new Set(profiles.map((p) => p.address).filter(Boolean))].sort(),
[profiles]
);
const availabilities = useMemo(
() => [...new Set(profiles.flatMap((p) => p.availability || []))].sort(),
[profiles]
);
const filtered = useMemo(() => {
const q = search.toLowerCase();
return profiles
.filter((p) => {
if (q && !`${p.full_name} ${p.email} ${p.desired_position} ${p.current_position} ${(p.skills || []).join(' ')}`.toLowerCase().includes(q)) return false;
if (skill !== 'all' && !(p.skills || []).includes(skill)) return false;
if (location !== 'all' && p.address !== location) return false;
if (availability !== 'all' && !(p.availability || []).includes(availability)) return false;
if (!BANDS[band](p.krow_score || 0)) return false;
if (experience === '5plus' && (p.experience_years || 0) < 5) return false;
if (experience === '2to5' && ((p.experience_years || 0) < 2 || (p.experience_years || 0) >= 5)) return false;
if (experience === 'under2' && (p.experience_years || 0) >= 2) return false;
return true;
})
.sort(SORTS[sort].compare);
}, [profiles, search, skill, experience, location, band, availability, sort]);
const isFiltered = Boolean(search) || [skill, experience, location, band, availability].some((v) => v !== 'all');
const clearFilters = () => {
setSearch(''); setSkill('all'); setExperience('all'); setLocation('all'); setBand('all'); setAvailability('all');
};
const segments = useMemo(() => {
const getBandMembers = (min, max) => profiles.filter((p) => {
const s = p.krow_score || 0;
return s >= min && (max == null || s < max);
});
return [
{ label: 'Elite', hint: '90+', members: getBandMembers(90), tone: 'brand' },
{ label: 'Excellent', hint: '75–89', members: getBandMembers(75, 90), tone: 'success' },
{ label: 'Solid', hint: '60–74', members: getBandMembers(60, 75), tone: 'default' },
{ label: 'Building', hint: 'under 60', members: getBandMembers(1, 60), tone: 'warning' },
{ label: 'Unscored', hint: 'no score', members: profiles.filter((p) => !(p.krow_score > 0)), tone: 'risk' },
].map((s) => ({
...s,
count: s.members.length,
available: s.members.filter((p) => (p.availability || []).length > 0).length,
avgExperience: (() => {
/* 0 years is "not stated", not "first year" — the cards that show it
gate on experience_years > 0, so the average is over the same set. */
const stated = s.members.filter((p) => (p.experience_years || 0) > 0);
return stated.length
? Math.round(stated.reduce((sum, p) => sum + p.experience_years, 0) / stated.length)
: 0;
})(),
}));
}, [profiles]);
const toggleSave = (id, name) => {
setSaved((prev) => {
const next = prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id];
toast.success(prev.includes(id) ? `${name} removed from saved` : `${name} saved`);
return next;
});
};
const context = useMemo(() => ({
profiles, segments, filtered, isLoading, isFiltered, clearFilters, saved, toggleSave,
search, setSearch, skill, setSkill, experience, setExperience, location, setLocation,
band, setBand, availability, setAvailability, sort, setSort,
skills, locations, availabilities,
}), [
profiles, segments, filtered, isLoading, isFiltered, saved,
search, skill, experience, location, band, availability, sort, skills, locations, availabilities,
]);
return (
);
}
/** The composed page. */
function TalentPoolComposition({ context }) {
const editing = useUiEditing();
const tree = editing?.tree || composePage('talent-pool').tree;
return ;
}