import type { ReactNode } from 'react';
import type { LucideIcon } from 'lucide-react';
import type { PageMeta } from './shared';
import { ChevronLeft, ChevronRight, Inbox, Loader2, Search } from 'lucide-react';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { STATUS_TONE, humanStatus } from './shared';

// Presentational furniture shared by every /invoices section. Nothing here fetches or mutates — these are
// the pieces the section views arrange.

/** Status pill. Unknown tokens fall through to the neutral tone rather than rendering unstyled. */
export const StatusBadge = ({ value, className = '' }: { value: string | null | undefined; className?: string }) => {
  if (!value) return null;
  const tone = STATUS_TONE[value] ?? 'bg-muted text-muted-foreground ring-border';
  return (
    <span
      className={`inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide ring-1 ring-inset ${tone} ${className}`}
    >
      {humanStatus(value)}
    </span>
  );
};

export const EmptyState = ({
  icon: Icon = Inbox,
  title,
  hint,
  action,
}: {
  icon?: LucideIcon;
  title: string;
  hint?: string;
  action?: ReactNode;
}) => (
  <div className="flex h-full flex-col items-center justify-center gap-3 p-10 text-center">
    <div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-muted text-muted-foreground">
      <Icon className="h-6 w-6" />
    </div>
    <div>
      <div className="text-sm font-medium">{title}</div>
      {hint && <div className="mt-1 max-w-sm text-xs text-muted-foreground">{hint}</div>}
    </div>
    {action}
  </div>
);

export const LoadingState = ({ label = 'Loading…' }: { label?: string }) => (
  <div className="flex h-full items-center justify-center gap-2 text-xs text-muted-foreground">
    <Loader2 className="h-4 w-4 animate-spin" />
    {label}
  </div>
);

export const ErrorState = ({ error, hint }: { error: unknown; hint?: string }) => (
  <div className="flex h-full flex-col items-center justify-center gap-2 p-10 text-center">
    <div className="text-sm font-medium text-red-500">Could not reach InvoiceShelf</div>
    <div className="max-w-md text-xs text-muted-foreground">
      {hint ?? 'Check the connection under Invoices → Connection, and that officer-invoiceshelf is running.'}
    </div>
    {error != null && (
      <pre className="max-w-md overflow-hidden text-ellipsis text-[10px] text-muted-foreground/70">
        {String((error as Error)?.message ?? error).slice(0, 300)}
      </pre>
    )}
  </div>
);

/**
 * Search box that writes straight through on every keystroke.
 *
 * Not debounced, deliberately: the query string is the source of truth, and react-query keys each distinct
 * search as its own cache entry, so backspacing through a term replays cached responses rather than
 * refiring requests. A debounce would only add lag to the first character.
 */
export const SearchBox = ({
  value,
  onChange,
  placeholder = 'Search…',
}: {
  value: string;
  onChange: (v: string) => void;
  placeholder?: string;
}) => (
  <div className="relative min-w-0 flex-1 sm:max-w-xs">
    <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
    <Input
      value={value}
      onChange={(e) => onChange(e.target.value)}
      placeholder={placeholder}
      className="h-8 pl-8 text-xs"
    />
  </div>
);

/** Horizontal status tabs above a list, each carrying the count when one is known. */
export const StatusTabs = <T extends string>({
  tabs,
  value,
  onChange,
}: {
  tabs: readonly { id: T | null; label: string; count?: number }[];
  value: T | null;
  onChange: (v: T | null) => void;
}) => (
  <div className="flex items-center gap-1 overflow-x-auto">
    {tabs.map((tab) => {
      const active = value === tab.id;
      return (
        <button
          key={tab.id ?? 'all'}
          type="button"
          onClick={() => onChange(tab.id)}
          className={`shrink-0 rounded-md px-2.5 py-1 text-xs transition-colors ${
            active ? 'bg-muted font-medium text-foreground' : 'text-muted-foreground hover:bg-muted/60'
          }`}
        >
          {tab.label}
          {tab.count != null && <span className="ml-1.5 tabular-nums opacity-60">{tab.count}</span>}
        </button>
      );
    })}
  </div>
);

/**
 * Pager for a Laravel-paginated list. Renders nothing on a single page — a lone disabled "1 of 1" is noise.
 */
export const Pagination = ({ meta, onPage }: { meta: PageMeta | null; onPage: (page: number) => void }) => {
  if (!meta || meta.last_page <= 1) return null;
  const { current_page, last_page, from, to, total } = meta;

  return (
    <div className="flex shrink-0 items-center justify-between gap-2 border-t border-border px-3 py-1.5 text-xs text-muted-foreground">
      <span className="tabular-nums">
        {from ?? 0}–{to ?? 0} of {total}
      </span>
      <div className="flex items-center gap-1">
        <Button
          variant="ghost"
          size="sm"
          className="h-7 px-2"
          disabled={current_page <= 1}
          onClick={() => onPage(current_page - 1)}
        >
          <ChevronLeft className="h-3.5 w-3.5" />
        </Button>
        <span className="tabular-nums">
          {current_page} / {last_page}
        </span>
        <Button
          variant="ghost"
          size="sm"
          className="h-7 px-2"
          disabled={current_page >= last_page}
          onClick={() => onPage(current_page + 1)}
        >
          <ChevronRight className="h-3.5 w-3.5" />
        </Button>
      </div>
    </div>
  );
};

/** Column contract for SimpleTable. `width` is a grid track ('1fr', '120px', 'minmax(0,2fr)'). */
export type Column<T> = {
  key: string;
  label: string;
  width: string;
  align?: 'left' | 'right' | 'center';
  render: (row: T) => ReactNode;
};

/**
 * The list table.
 *
 * A CSS grid rather than a <table>: every list here shares a sticky header and a single scroller, and grid
 * tracks keep the two aligned without the colgroup gymnastics a real table needs. Not virtualised — these
 * lists are server-paginated, so the row count on screen is bounded by `limit`.
 */
export const SimpleTable = <T,>({
  rows,
  columns,
  rowKey,
  selectedKey,
  onRowClick,
  rowMenu,
  empty,
}: {
  rows: T[];
  columns: Column<T>[];
  rowKey: (row: T) => number | string;
  selectedKey?: number | string | null;
  onRowClick?: (row: T) => void;
  rowMenu?: (row: T) => ReactNode;
  empty?: ReactNode;
}) => {
  const template = columns.map((c) => c.width).join(' ') + (rowMenu ? ' 40px' : '');

  if (!rows.length && empty) return <>{empty}</>;

  return (
    <div className="h-full overflow-auto">
      <div
        className="sticky top-0 z-10 grid border-b border-border bg-background/95 backdrop-blur"
        style={{ gridTemplateColumns: template }}
      >
        {columns.map((col) => (
          <div
            key={col.key}
            className={`overflow-hidden px-3 py-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground ${
              col.align === 'right' ? 'text-right' : col.align === 'center' ? 'text-center' : ''
            }`}
          >
            <span className="truncate">{col.label}</span>
          </div>
        ))}
        {rowMenu && <div />}
      </div>

      <div>
        {rows.map((row) => {
          const key = rowKey(row);
          const isSelected = selectedKey != null && key === selectedKey;
          return (
            <div
              key={key}
              onClick={() => onRowClick?.(row)}
              className={`grid items-center border-b border-border/40 text-xs transition-colors ${
                onRowClick ? 'cursor-pointer' : ''
              } ${isSelected ? 'bg-primary/10' : 'hover:bg-muted/50'}`}
              style={{ gridTemplateColumns: template }}
            >
              {columns.map((col) => (
                <div
                  key={col.key}
                  className={`min-w-0 overflow-hidden px-3 py-2 ${
                    col.align === 'right' ? 'text-right tabular-nums' : col.align === 'center' ? 'text-center' : ''
                  }`}
                >
                  {col.render(row)}
                </div>
              ))}
              {rowMenu && (
                <div className="flex items-center justify-center" onClick={(e) => e.stopPropagation()}>
                  {rowMenu(row)}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
};

/** Label/value row for the detail panes. */
export const Field = ({ label, children }: { label: string; children: ReactNode }) => (
  <div className="flex items-baseline justify-between gap-3 py-1 text-xs">
    <span className="shrink-0 text-muted-foreground">{label}</span>
    <span className="min-w-0 truncate text-right">{children}</span>
  </div>
);

export const SectionShell = ({
  toolbar,
  children,
  footer,
}: {
  toolbar?: ReactNode;
  children: ReactNode;
  footer?: ReactNode;
}) => (
  <div className="flex h-full min-h-0 flex-col">
    {toolbar && (
      <div className="flex shrink-0 flex-wrap items-center gap-2 border-b border-border px-3 py-2">{toolbar}</div>
    )}
    <div className="min-h-0 flex-1">{children}</div>
    {footer}
  </div>
);
