'use client';

import { Loader2 } from 'lucide-react';

import { Button } from '@/components/ui/button';
import type {
  AggregatedFile,
  AggregatedGroup,
  AggregatedWorkflow,
} from '@/hooks/use-aggregated-listing';

/**
 * Discriminated-union of the two item shapes the aggregated projection
 * surfaces (files / workflows). Keeps `renderRow` strictly typed so callers
 * don't have to widen to `unknown` or recast inside the row renderer.
 */
type AggregatedItemKind =
  | { kind: 'files'; items: AggregatedFile[] }
  | { kind: 'workflows'; items: AggregatedWorkflow[] };

type ItemOfKind<K extends AggregatedItemKind['kind']> = Extract<
  AggregatedItemKind,
  { kind: K }
>['items'][number];

interface AggregatedSectionProps<K extends AggregatedItemKind['kind']> {
  title: string;
  icon?: React.ReactNode;
  groups: AggregatedGroup<ItemOfKind<K>>[];
  renderRow: (item: ItemOfKind<K>, group: AggregatedGroup<ItemOfKind<K>>) => React.ReactNode;
  emptyMessage?: string;
  loading?: boolean;
  onShowAll?: (group: AggregatedGroup<ItemOfKind<K>>) => void;
}

/**
 * Renders a Signing or Files section with one labelled subsection per
 * owner-source group. Each group shows up to 20 rows; a `Show all (N)`
 * link drills into the source-scoped flat list. Hidden when groups is
 * empty.
 */
export function AggregatedSection<K extends AggregatedItemKind['kind']>({
  title,
  icon,
  groups,
  renderRow,
  emptyMessage = 'Nothing here yet.',
  loading,
  onShowAll,
}: AggregatedSectionProps<K>) {
  const total = groups.reduce((sum, g) => sum + g.total, 0);

  if (loading) {
    return (
      <section className="rounded-md border bg-white p-3">
        <h3 className="flex items-center gap-2 text-sm font-semibold text-foreground">
          {icon}
          {title}
          <Loader2 className="ml-1 h-3.5 w-3.5 animate-spin text-muted-foreground" />
        </h3>
      </section>
    );
  }

  if (groups.length === 0) {
    return (
      <section className="rounded-md border bg-white p-3 text-sm text-muted-foreground">
        <h3 className="flex items-center gap-2 text-sm font-semibold text-foreground">
          {icon}
          {title}
          <span className="ml-1 text-xs text-muted-foreground tabular-nums">· 0</span>
        </h3>
        <p className="mt-2">{emptyMessage}</p>
      </section>
    );
  }

  return (
    <section className="rounded-md border bg-white">
      <h3 className="flex items-center gap-2 border-b px-3 py-2 text-sm font-semibold text-foreground">
        {icon}
        {title}
        <span className="ml-1 text-xs text-muted-foreground tabular-nums">· {total}</span>
      </h3>
      <div className="divide-y">
        {groups.map((g) => (
          <GroupBlock<K>
            key={`${g.source}-${g.label}`}
            group={g}
            renderRow={renderRow}
            onShowAll={onShowAll}
          />
        ))}
      </div>
    </section>
  );
}

function GroupBlock<K extends AggregatedItemKind['kind']>({
  group,
  renderRow,
  onShowAll,
}: {
  group: AggregatedGroup<ItemOfKind<K>>;
  renderRow: (item: ItemOfKind<K>, group: AggregatedGroup<ItemOfKind<K>>) => React.ReactNode;
  onShowAll?: (group: AggregatedGroup<ItemOfKind<K>>) => void;
}) {
  // The server always sets exactly one of `files` / `workflows` per group;
  // unify them into a single list for rendering. The discriminated-union
  // generic on `AggregatedSection` keeps the row type correct upstream.
  const items = ((group.files ?? group.workflows ?? []) as unknown) as ItemOfKind<K>[];
  return (
    <div className="px-3 py-2">
      <header className="mb-1 text-[0.7rem] font-medium uppercase tracking-wide text-muted-foreground">
        {group.label}
        <span className="ml-1.5 text-muted-foreground/70 tabular-nums">· {group.total}</span>
      </header>
      <ul className="space-y-1">
        {items.map((item) => (
          <li key={(item as { id: string }).id}>{renderRow(item, group)}</li>
        ))}
      </ul>
      {group.total > items.length ? (
        <Button
          variant="ghost"
          size="sm"
          className="mt-1 min-h-[44px] px-2 text-xs text-brand hover:underline"
          onClick={() => onShowAll?.(group)}
        >
          Show all ({group.total})
        </Button>
      ) : null}
    </div>
  );
}
