'use client';

import {useMemo, useState} from 'react';
import {Grid} from '@astryxdesign/core/Grid';
import {AsyncBoundary} from '@/components/data/AsyncBoundary';
import {FilterBar} from '@/components/patterns/FilterBar';
import {CollectionRegion} from '@/components/patterns/CollectionRegion';
import {EmptyPanel} from '@/components/patterns/EmptyPanel';
import {SkeletonCardGrid} from '@/components/patterns/LoadingState';
import {StaffCard} from './StaffCard';
import {ATTENDANCE} from './attendance';
import type {Attendance, StaffMember} from '@/lib/api/contracts';
import type {Resource} from '@/lib/api/useResource';

type Filter = 'all' | Attendance;

const STAFF_GRID_COLUMNS = {minWidth: 300, max: 3, repeat: 'fit'} as const;

export function StaffGrid({resource}: {resource: Resource<StaffMember[]>}) {
  const [query, setQuery] = useState('');
  const [filter, setFilter] = useState<Filter>('all');

  // `?? []` allocates a fresh array every render, which would make it an
  // unstable dependency and recompute both memos on every keystroke.
  const staff = useMemo(() => resource.data ?? [], [resource.data]);

  const counts = useMemo(() => {
    const c: Record<Filter, number> = {
      all: staff.length,
      present: 0,
      late: 0,
      absent: 0,
      leave: 0,
    };
    for (const m of staff) c[m.attendance] += 1;
    return c;
  }, [staff]);

  const visible = useMemo(() => {
    const q = query.trim().toLowerCase();
    return staff
      .filter(
        (m) =>
          (filter === 'all' || m.attendance === filter) &&
          (q === '' ||
            m.name.toLowerCase().includes(q) ||
            m.role.toLowerCase().includes(q)),
      )
      // Best performers first — the roster's default question is "who is
      // carrying this store", not "who was added first".
      .sort((a, b) => b.performanceScore - a.performanceScore);
  }, [staff, query, filter]);

  return (
    <CollectionRegion label="Team roster">
      <FilterBar
        query={query}
        onQueryChange={setQuery}
        placeholder="Search name or role…"
        filterValue={filter}
        onFilterChange={(v) => setFilter(v as Filter)}
        filterLabel="Filter staff by attendance"
        options={[
          {value: 'all', label: 'All', hint: counts.all},
          {value: 'present', label: ATTENDANCE.present.label, hint: counts.present},
          {value: 'late', label: ATTENDANCE.late.label, hint: counts.late},
          {value: 'absent', label: ATTENDANCE.absent.label, hint: counts.absent},
          {value: 'leave', label: ATTENDANCE.leave.label, hint: counts.leave},
        ]}
        resultCount={visible.length}
        resultNoun={visible.length === 1 ? 'person' : 'people'}
      />

      <AsyncBoundary
        resource={resource}
        loading={<SkeletonCardGrid count={6} height={230} minWidth={300} />}
        empty={
          <EmptyPanel
            icon="staff"
            title="No staff yet"
            description="Team members appear here once they are added to a store."
          />
        }
      >
        {() =>
          visible.length === 0 ? (
            <EmptyPanel
              icon="staff"
              title="Nobody matches"
              description="Try a different attendance filter or clear the search."
            />
          ) : (
            <Grid columns={STAFF_GRID_COLUMNS} gap={4}>
              {visible.map((m) => (
                <StaffCard key={m.id} member={m} />
              ))}
            </Grid>
          )
        }
      </AsyncBoundary>
    </CollectionRegion>
  );
}
