'use client';

import {useMemo, useState} from 'react';
import {Grid} from '@astryxdesign/core/Grid';
import {AsyncBoundary} from '@/shared/components/data/AsyncBoundary';
import {FilterBar} from '@/shared/components/patterns/FilterBar';
import {CollectionRegion} from '@/shared/components/patterns/CollectionRegion';
import {EmptyPanel} from '@/shared/components/patterns/EmptyPanel';
import {SkeletonCardGrid} from '@/shared/components/patterns/LoadingState';
import {RewardCard} from './RewardCard';
import type {Reward, RewardStatus} from '@/features/lyts/types/reward';
import type {Resource} from '@/shared/hooks/useResource';

type Filter = 'all' | RewardStatus;

const REWARD_GRID_COLUMNS = {minWidth: 270, max: 3, repeat: 'fit'} as const;

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

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

  // Counts come from the unfiltered set so the chips still read "Expiring (2)"
  // while another filter is active.
  const counts = useMemo(() => {
    const c: Record<Filter, number> = {
      all: rewards.length,
      active: 0,
      paused: 0,
      expiring: 0,
      expired: 0,
    };
    for (const r of rewards) c[r.status] += 1;
    return c;
  }, [rewards]);

  const visible = useMemo(() => {
    const q = query.trim().toLowerCase();
    return rewards.filter(
      (r) =>
        (filter === 'all' || r.status === filter) &&
        (q === '' || r.name.toLowerCase().includes(q)),
    );
  }, [rewards, query, filter]);

  return (
    <CollectionRegion label="Reward catalogue">
      <FilterBar
        query={query}
        onQueryChange={setQuery}
        placeholder="Search rewards…"
        filterValue={filter}
        onFilterChange={(v) => setFilter(v as Filter)}
        filterLabel="Filter rewards by status"
        options={[
          {value: 'all', label: 'All', hint: counts.all},
          {value: 'active', label: 'Active', hint: counts.active},
          {value: 'expiring', label: 'Expiring', hint: counts.expiring},
          {value: 'paused', label: 'Paused', hint: counts.paused},
          {value: 'expired', label: 'Expired', hint: counts.expired},
        ]}
        resultCount={visible.length}
        resultNoun={visible.length === 1 ? 'reward' : 'rewards'}
      />

      <AsyncBoundary
        resource={resource}
        loading={<SkeletonCardGrid count={6} height={230} />}
        empty={
          <EmptyPanel
            icon="lyts"
            title="No rewards yet"
            description="Create a reward to let customers spend their LYTs in store."
          />
        }
      >
        {() =>
          visible.length === 0 ? (
            <EmptyPanel
              icon="lyts"
              title="No rewards match"
              description="Try a different status filter or clear the search."
            />
          ) : (
            <Grid columns={REWARD_GRID_COLUMNS} gap={4}>
              {visible.map((r) => (
                <RewardCard key={r.id} reward={r} nowMs={nowMs} />
              ))}
            </Grid>
          )
        }
      </AsyncBoundary>
    </CollectionRegion>
  );
}
