'use client';

/**
 * Feedback - section 5 of /design-system.
 *
 * Live demos for EmptyState, ErrorState, Spinner, Skeleton,
 * InlineNotice, and ErrorBoundary (with a "Throw error" trigger).
 */

import { useState, useCallback, type ReactNode } from 'react';
import { EmailVerificationBanner } from '@/components/ui/feedback/EmailVerificationBanner';
import { EmptyState } from '@/components/ui/feedback/EmptyState';
import { ErrorState } from '@/components/ui/feedback/ErrorState';
import { Spinner } from '@/components/ui/feedback/Spinner';
import {
  Skeleton,
  BrowseCardSkeleton,
  ProfileSkeleton,
  CartSkeleton,
  TableSkeleton,
} from '@/components/ui/feedback/Skeleton';
import { LoadingOverlay } from '@/components/ui/feedback/LoadingOverlay';
import { InlineNotice } from '@/components/ui/feedback/InlineNotice';
import { ErrorBoundary } from '@/components/ui/feedback/ErrorBoundary';
import { PullToRefresh } from '@/components/ui/feedback/PullToRefresh';
import { RetryPanel } from '@/components/ui/feedback/RetryPanel';
import { Button } from '@/components/ui/primitives/Button';
import { Stack } from '@/components/ui/layout/Stack';
import { Row } from '@/components/ui/layout/Row';
import { Icon } from '@/components/ui/icons/Icon';
import { useT } from '@/lib/i18n/react';
import { ComponentEntry } from '../../components/ComponentEntry';
import { SectionShell } from '../../components/SectionShell';

function ThrowingChild({ shouldThrow }: { shouldThrow: boolean }): ReactNode {
  if (shouldThrow) {
    throw new Error('Demo error from <ThrowingChild>');
  }
  return (
    <p className="text-text-secondary text-sm">
      Child rendered without error. Click the button to make it throw.
    </p>
  );
}

function ErrorBoundaryDemo() {
  const [shouldThrow, setShouldThrow] = useState(false);
  const [key, setKey] = useState(0);
  const reset = useCallback(() => {
    setShouldThrow(false);
    setKey((k) => k + 1);
  }, []);

  return (
    <Stack gap="3">
      <Row gap="2">
        <Button variant="danger" onClick={() => setShouldThrow(true)}>
          Throw error
        </Button>
        <Button variant="secondary" onClick={reset}>
          Reset
        </Button>
      </Row>
      <ErrorBoundary key={key}>
        <ThrowingChild shouldThrow={shouldThrow} />
      </ErrorBoundary>
    </Stack>
  );
}

export function Feedback() {
  const t = useT('design_system');

  return (
    <SectionShell id="feedback" title={t('sidebar_feedback')} description={t('section_intro')}>
      {/* EmptyState */}
      <ComponentEntry
        name="EmptyState"
        id="emptystate-feedback"
        path="src/components/ui/feedback/EmptyState"
        description="Empty list / zero-data state with optional icon, description, and CTA."
        tokens={['color-text-muted', 'space-3', 'space-6', 'space-10']}
        a11yNotes={[
          'Title is the only h-level - uses surrounding heading hierarchy',
          'Action slot accepts Button',
        ]}
        importSnippet={`import { EmptyState } from '@/components/ui/feedback/EmptyState';`}
      >
        <EmptyState
          icon={<Icon name="ShoppingBag" size="lg" color="muted" />}
          title="אין כאן כלום עדיין"
          description="ברגע שיהיו עסקאות הן יופיעו כאן."
          action={<Button>רענן</Button>}
        />
      </ComponentEntry>

      {/* ErrorState */}
      <ComponentEntry
        name="ErrorState"
        id="errorstate-feedback"
        path="src/components/ui/feedback/ErrorState"
        description="Error / failure state with danger tone and retry action."
        tokens={['color-danger-600', 'color-danger-50']}
        a11yNotes={['role=alert on the message', 'Action slot for retry']}
        importSnippet={`import { ErrorState } from '@/components/ui/feedback/ErrorState';`}
      >
        <ErrorState
          title="משהו השתבש"
          description="לא הצלחנו לטעון את הנתונים."
          action={<Button variant="danger">נסה שוב</Button>}
        />
      </ComponentEntry>

      {/* Spinner */}
      <ComponentEntry
        name="Spinner"
        id="spinner-feedback"
        path="src/components/ui/feedback/Spinner"
        description="5-variant animated loading indicator. Variant auto-selected by route via RouteSpinnerProvider. Respects prefers-reduced-motion."
        tokens={[
          'color-brand-primary-700',
          'color-brand-primary-900',
          'color-brand-primary-200',
          'color-neutral-200',
          'color-surface-base',
        ]}
        a11yNotes={[
          'role=status on wrapper',
          'sr-only label always rendered (prop or default "טוען…")',
          'Inner visuals are aria-hidden',
          'All animations disabled on prefers-reduced-motion',
          'spot: animation-direction reverses in :dir(rtl)',
        ]}
        importSnippet={`import { Spinner, RouteSpinnerProvider, useSpinnerVariant } from '@/components/ui/feedback/Spinner';`}
      >
        <Stack gap="4">
          <div>
            <p className="text-text-muted mb-2 text-sm font-medium">
              bounce (default) — 3 marks staggered
            </p>
            <Row gap="6" align="center">
              <Spinner variant="bounce" size="sm" label="bounce sm" />
              <Spinner variant="bounce" size="md" label="bounce md" />
              <Spinner variant="bounce" size="lg" label="bounce lg" />
            </Row>
          </div>
          <div>
            <p className="text-text-muted mb-2 text-sm font-medium">
              dots — logo + 3 bouncing dots (/account, /vendor routes)
            </p>
            <Row gap="6" align="center">
              <Spinner variant="dots" size="sm" label="dots sm" />
              <Spinner variant="dots" size="md" label="dots md" />
              <Spinner variant="dots" size="lg" label="dots lg" />
            </Row>
          </div>
          <div>
            <p className="text-text-muted mb-2 text-sm font-medium">
              bar — logo + indeterminate bar (/admin routes)
            </p>
            <Row gap="6" align="center">
              <Spinner variant="bar" size="sm" label="bar sm" />
              <Spinner variant="bar" size="md" label="bar md" />
              <Spinner variant="bar" size="lg" label="bar lg" />
            </Row>
          </div>
          <div>
            <p className="text-text-muted mb-2 text-sm font-medium">
              spot — conic orbit, RTL reverses (/__splash, /loading)
            </p>
            <Row gap="6" align="center">
              <Spinner variant="spot" size="sm" label="spot sm" />
              <Spinner variant="spot" size="md" label="spot md" />
              <Spinner variant="spot" size="lg" label="spot lg" />
            </Row>
          </div>
          <div>
            <p className="text-text-muted mb-2 text-sm font-medium">
              inline — tiny dots only, no mark (buttons / tight slots)
            </p>
            <Row gap="4" align="center">
              <Spinner variant="inline" label="inline" />
              <button
                type="button"
                className="bg-brand-primary-700 inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm text-white"
                disabled
              >
                שומר <Spinner variant="inline" label="שומר…" />
              </button>
            </Row>
          </div>
        </Stack>
      </ComponentEntry>

      {/* Skeleton */}
      <ComponentEntry
        name="Skeleton"
        id="skeleton-feedback"
        path="src/components/ui/feedback/Skeleton"
        description="Pulsing placeholder base. rect / circle / text variants. Uses --color-skeleton-base token."
        tokens={[
          'color-skeleton-base',
          'color-skeleton-shine',
          'radius-md',
          'radius-sm',
          'radius-full',
        ]}
        a11yNotes={[
          'aria-hidden + role=presentation — purely visual',
          'Pulse animation disabled on prefers-reduced-motion',
        ]}
        importSnippet={`import { Skeleton } from '@/components/ui/feedback/Skeleton';`}
      >
        <Stack gap="2">
          <Skeleton className="h-4 w-32" />
          <Skeleton className="h-4 w-48" />
          <Skeleton className="h-4 w-24" />
          <Row gap="3" align="center">
            <Skeleton variant="circle" className="h-10 w-10" />
            <Skeleton variant="text" className="w-40" />
          </Row>
        </Stack>
      </ComponentEntry>

      {/* BrowseCardSkeleton */}
      <ComponentEntry
        name="BrowseCardSkeleton"
        id="browsecardskeleton-feedback"
        path="src/components/ui/feedback/Skeleton/BrowseCardSkeleton"
        description="Loading placeholder mirroring DealCard.astro browse-grid geometry (aspect-square + footer strip)."
        tokens={['color-skeleton-base', 'color-surface-base', 'color-brand-primary-50']}
        a11yNotes={['role=status with sr-only loading label']}
        importSnippet={`import { BrowseCardSkeleton } from '@/components/ui/feedback/Skeleton';`}
      >
        <div className="w-48">
          <BrowseCardSkeleton />
        </div>
      </ComponentEntry>

      {/* ProfileSkeleton */}
      <ComponentEntry
        name="ProfileSkeleton"
        id="profileskeleton-feedback"
        path="src/components/ui/feedback/Skeleton/ProfileSkeleton"
        description="Loading placeholder for the profile page."
        tokens={['color-skeleton-base']}
        a11yNotes={['aria-hidden + role=presentation']}
        importSnippet={`import { ProfileSkeleton } from '@/components/ui/feedback/Skeleton';`}
      >
        <ProfileSkeleton />
      </ComponentEntry>

      {/* CartSkeleton */}
      <ComponentEntry
        name="CartSkeleton"
        id="cartskeleton-feedback"
        path="src/components/ui/feedback/Skeleton/CartSkeleton"
        description="Loading placeholder for the cart page."
        tokens={['color-skeleton-base', 'color-border-default']}
        a11yNotes={['aria-hidden + role=presentation']}
        importSnippet={`import { CartSkeleton } from '@/components/ui/feedback/Skeleton';`}
      >
        <CartSkeleton />
      </ComponentEntry>

      {/* TableSkeleton */}
      <ComponentEntry
        name="TableSkeleton"
        id="tableskeleton-feedback"
        path="src/components/ui/feedback/Skeleton/TableSkeleton"
        description="Loading placeholder for admin tables. cols + rows props."
        tokens={['color-skeleton-base', 'color-surface-inset']}
        a11yNotes={['aria-hidden + role=presentation', 'cols/rows configurable']}
        importSnippet={`import { TableSkeleton } from '@/components/ui/feedback/Skeleton';`}
      >
        <TableSkeleton cols={4} rows={3} />
      </ComponentEntry>

      {/* LoadingOverlay */}
      <ComponentEntry
        name="LoadingOverlay"
        id="loadingoverlay-feedback"
        path="src/components/ui/feedback/LoadingOverlay"
        description="Full-viewport blocking spinner shown during long async work. Multideal hard rule: spinners NEVER render inline inside buttons — always show as a full-screen overlay. Mounted once inside HydratedIsland; any island can drive it via useLoadingOverlay().show(label) / .hide()."
        tokens={['color-surface-base', 'color-text-primary', 'space-4', 'z-50']}
        a11yNotes={[
          'role=status + aria-live=polite — screen readers announce label on appear',
          'aria-busy=true on overlay container',
          'Backdrop blocks pointer events — work below cannot be interacted with',
          'Counter-based store: concurrent show() calls coalesce; overlay hides only when all hide()',
        ]}
        importSnippet={`import { LoadingOverlay, useLoadingOverlay } from '@/components/ui/feedback/LoadingOverlay';`}
      >
        <div className="border-border-default relative h-40 overflow-hidden rounded-md border">
          <p className="text-text-muted p-4 text-sm">
            (Demo — overlay rendered with `open` prop, not the global store.)
          </p>
          <LoadingOverlay open label="Saving..." className="!absolute" />
        </div>
      </ComponentEntry>

      {/* InlineNotice */}
      <ComponentEntry
        name="InlineNotice"
        id="inlinenotice-feedback"
        path="src/components/ui/feedback/InlineNotice"
        description="Banner-style contextual notice. Tones: success / warning / danger / info."
        tokens={['color-success-50', 'color-warning-50', 'color-danger-50', 'color-info-50']}
        a11yNotes={[
          'role=status (info/success) or role=alert (warning/danger)',
          'Title + description structure',
        ]}
        importSnippet={`import { InlineNotice } from '@/components/ui/feedback/InlineNotice';`}
      >
        <Stack gap="3">
          <InlineNotice tone="success" title="הצלחה" description="הפעולה בוצעה בהצלחה." />
          <InlineNotice tone="warning" title="שים לב" description="העסקה פגה תוך שעה." />
          <InlineNotice tone="danger" title="שגיאה" description="לא הצלחנו לעבד את התשלום." />
          <InlineNotice tone="info" title="מידע" description="מולטידיל משלמת לעסקים תוך 7 ימים." />
        </Stack>
      </ComponentEntry>

      {/* ErrorBoundary */}
      <ComponentEntry
        name="ErrorBoundary"
        id="errorboundary-feedback"
        path="src/components/ui/feedback/ErrorBoundary"
        description="React error boundary that catches subtree errors and renders an ErrorState."
        tokens={['color-danger-600']}
        a11yNotes={['Falls back to ErrorState (role=alert)', 'Use a `key` to force-reset on retry']}
        importSnippet={`import { ErrorBoundary } from '@/components/ui/feedback/ErrorBoundary';`}
      >
        <ErrorBoundaryDemo />
      </ComponentEntry>

      {/* EmailVerificationBanner */}
      <ComponentEntry
        name="EmailVerificationBanner"
        id="emailverificationbanner-feedback"
        path="src/components/ui/feedback/EmailVerificationBanner"
        description="Sticky soft-gate banner for unverified email. Shows resend CTA and a per-session dismiss button. Dismissal persists in sessionStorage — resurfaces on next session."
        tokens={['color-warning-50', 'color-warning-500', 'color-warning-700', 'z-40']}
        a11yNotes={[
          'role=region with aria-label → screen readers announce region title',
          'aria-live=polite → changes announced non-interruptively',
          'Resend button: loading prop sets aria-busy=true + disabled',
          'Dismiss button: aria-label matches i18n key verify_email_banner_dismiss',
          'No inline spinner (hard rule) — loading state via aria-busy only',
        ]}
        importSnippet={`import { EmailVerificationBanner } from '@/components/ui/feedback/EmailVerificationBanner';`}
      >
        <Stack gap="3">
          <div>
            <p className="text-text-muted mb-2 text-sm">idle state</p>
            <EmailVerificationBanner
              email="user@example.com"
              onResend={() => Promise.resolve()}
              resending={false}
            />
          </div>
          <div>
            <p className="text-text-muted mb-2 text-sm">
              resending state (button disabled + aria-busy)
            </p>
            <EmailVerificationBanner
              email="user@example.com"
              onResend={() => new Promise(() => undefined)}
              resending
            />
          </div>
          <p className="text-text-muted text-sm">
            dismissed state: click Dismiss above — banner hides immediately and sessionStorage flag
            is set. Reloading the page restores it (sessionStorage clears on tab close).
          </p>
        </Stack>
      </ComponentEntry>

      {/* RetryPanel */}
      <ComponentEntry
        name="RetryPanel"
        id="retrypanel-feedback"
        path="src/components/ui/feedback/RetryPanel"
        description="Retry fallback for ErrorBoundary wrapping lazy-loaded chunks. Renders title + retry Button. Variants: card (default), inline."
        tokens={[
          'color-border-default',
          'color-surface-base',
          'color-text-primary',
          'space-3',
          'space-6',
        ]}
        a11yNotes={[
          'role=alert announces the failure',
          'Retry rendered as shared <Button>; keyboard + screen-reader friendly',
          'RefreshCw icon mirrors in RTL via Icon.mirror',
        ]}
        importSnippet={`import { RetryPanel } from '@/components/ui/feedback/RetryPanel';`}
      >
        <Stack gap="3">
          <div>
            <p className="text-text-muted mb-2 text-sm">variant=card (default)</p>
            <RetryPanel onRetry={() => undefined} />
          </div>
          <div>
            <p className="text-text-muted mb-2 text-sm">variant=card with custom message</p>
            <RetryPanel onRetry={() => undefined} message="לא הצלחנו לטעון את העסקה" />
          </div>
          <div>
            <p className="text-text-muted mb-2 text-sm">variant=inline</p>
            <RetryPanel onRetry={() => undefined} variant="inline" />
          </div>
        </Stack>
      </ComponentEntry>

      {/* PullToRefresh */}
      <ComponentEntry
        name="PullToRefresh"
        id="pulltorefresh-feedback"
        path="src/components/ui/feedback/PullToRefresh"
        description="Custom pull-to-refresh gesture restored for installed PWA users on iOS and Android. Self-gates on display-mode: standalone (or legacy iOS navigator.standalone) and prefers-reduced-motion; renders null in browser tabs. Mounted once via AppShell for customer mode."
        tokens={[
          'color-surface-base',
          'color-text-primary',
          'color-brand-primary-600',
          'shadow-md',
          'z-overlay',
        ]}
        a11yNotes={[
          'role=status with aria-live=polite announces refresh state',
          'aria-hidden flips to false only while pulling',
          'Hard-gated off when prefers-reduced-motion: reduce',
          'No preventDefault on touch — never blocks native scroll',
          'Only arms when window.scrollY === 0 — never hijacks mid-scroll content',
        ]}
        importSnippet={`import { PullToRefresh } from '@/components/ui/feedback/PullToRefresh';`}
      >
        <Stack gap="3">
          <p className="text-text-muted text-sm">
            Live demo — uses a no-op onRefresh so the page does not reload. Component renders null
            unless the page is installed as a PWA (display-mode: standalone). When mounted in a
            browser tab, the gallery cell stays empty by design. Pull from the very top of the
            viewport to engage.
          </p>
          <PullToRefresh onRefresh={() => Promise.resolve()} />
        </Stack>
      </ComponentEntry>
    </SectionShell>
  );
}
