import { AlertTriangle, Bell, Loader2, PlayCircle, RotateCw } from 'lucide-react';

import { useEffect, useState } from 'react';

import { router } from '@inertiajs/react';

import { Button } from '@/Components/ui/button';
import { Progress } from '@/Components/ui/progress';
import { useGscSyncNotification } from '@/hooks/useGscSyncNotification';
import { SYNC_ESTIMATE_COPY } from '@/lib/copy/gsc';

import { syncStageCopy } from '../helpers';

interface GscSyncStatusCompactProps {
  /**
   * Real sync progress (0–100) derived server-side from last_sync_stage.
   * `null` means the job hasn't reported a stage yet (queued / cold-start);
   * render an indeterminate state instead of a misleading literal "5%".
   */
  syncProgressPct?: number | null;
  syncStage?: string | null;
  /** ISO timestamp when the current sync was dispatched. */
  syncStartedAt?: string | null;
  /** Server has decided this sync has exceeded the soft "stuck" threshold. */
  isStuck?: boolean;
  productOverviewVideoUrl?: string | null;
  propertyUrl?: string;
  siteId?: string;
}

/**
 * UX-218: Minute-only elapsed label.
 * Seconds precision was misleading because the interval only ticks every 60s.
 * - Under 60 s → "less than a minute"
 * - 1 min+     → "about Nm"
 */
function formatElapsed(ms: number): string {
  const minutes = Math.floor(Math.max(0, ms) / 60_000);
  if (minutes === 0) return 'less than a minute';
  return `about ${minutes}m`;
}

const STAGE_LABELS: Record<string, string> = {
  daily: 'Fetching daily traffic totals',
  dimensioned: 'Fetching device/country/search-type breakdowns',
  pages: 'Fetching per-page metrics + top queries',
  complete: 'Finishing up',
};

/**
 * Compact non-blocking sync indicator shown inline inside the GSC card.
 *
 * Renders:
 *   1. Connection confirmation + numeric (or indeterminate) progress.
 *   2. Real stage breadcrumb sourced from server.
 *   3. Live elapsed-time counter (so the user can self-diagnose "stuck").
 *   4. Retry CTA once `is_stuck` flips true.
 *   5. Notification opt-in for users who walk away.
 *   6. Product education for users who stay.
 */
export function GscSyncStatusCompact({
  syncProgressPct = null,
  syncStage = null,
  syncStartedAt = null,
  isStuck = false,
  productOverviewVideoUrl,
  propertyUrl,
  siteId,
}: GscSyncStatusCompactProps) {
  const isIndeterminate = syncProgressPct === null || syncProgressPct === undefined;
  const displayPct = isIndeterminate ? 0 : Math.min(100, Math.max(0, syncProgressPct));

  // Live elapsed-time counter — the single most useful signal a user has for
  // "is this still working or actually stuck".
  // A11Y-003: changed from 1000ms to 60000ms (1 minute) so screen readers
  // honouring polite live regions aren't overwhelmed by per-second ticks.
  const [now, setNow] = useState(() => Date.now());
  useEffect(() => {
    if (!syncStartedAt) return;
    const interval = window.setInterval(() => setNow(Date.now()), 60_000);
    return () => window.clearInterval(interval);
  }, [syncStartedAt]);

  const elapsedMs = syncStartedAt ? now - new Date(syncStartedAt).getTime() : null;
  const elapsedLabel = elapsedMs !== null && elapsedMs >= 0 ? formatElapsed(elapsedMs) : null;

  // COPY-001: data-grounded time estimate.
  // Under 3 minutes → reassuring concrete estimate.
  // Over 3 minutes → honest "taking a bit longer" (avoids false alarm while
  // acknowledging the wait, without triggering worst-case imagination).
  const LONG_SYNC_THRESHOLD_MS = 3 * 60 * 1000;
  const isLongSync = elapsedMs !== null && elapsedMs > LONG_SYNC_THRESHOLD_MS;
  const waitCopy = isLongSync
    ? 'Taking a bit longer than usual — still working.'
    : `Usually ${SYNC_ESTIMATE_COPY}.`;

  // Toast-providing click handler. Parent owns the completion-side
  // notification fire; passing isSyncing:false here keeps the transition
  // watcher idle to avoid double-firing.
  const { requestPermissionWithFeedback } = useGscSyncNotification({
    isSyncing: false,
    siteName: null,
  });

  const [retrying, setRetrying] = useState(false);
  const handleRetry = () => {
    if (!siteId) return;
    setRetrying(true);
    router.post(
      route('gsc.retry-sync', { site: siteId }),
      {},
      { preserveScroll: true, onFinish: () => setRetrying(false) },
    );
  };

  let notifSettingsHref: string | null = null;
  if (siteId) {
    try {
      notifSettingsHref = route('notification-settings.show', { site: siteId });
    } catch {
      // Route name not registered in Ziggy manifest (e.g. feature flag off).
    }
  }

  const stageDescription =
    syncStage && STAGE_LABELS[syncStage] ? STAGE_LABELS[syncStage] : syncStageCopy(displayPct);

  return (
    <div className="space-y-2">
      {/* UX-214: text-success-strong (>7:1) instead of text-success (~3.3:1 — below WCAG AA) */}
      {propertyUrl && <p className="text-sm text-success-strong">Connected: {propertyUrl}</p>}
      <div className="flex items-center gap-2">
        <Loader2 className="size-4 text-primary animate-spin shrink-0" aria-hidden="true" />
        <div>
          <span className="text-sm font-medium">Syncing in background</span>
          <span className="ml-1.5 text-xs text-muted-foreground" aria-live="polite">
            {isIndeterminate ? '— starting up…' : `— ${displayPct}% complete`}
          </span>
        </div>
      </div>
      <div
        role="progressbar"
        aria-valuenow={isIndeterminate ? undefined : displayPct}
        aria-valuemin={0}
        aria-valuemax={100}
        aria-label="GSC sync progress"
        aria-busy={isIndeterminate ? true : undefined}
      >
        {/* When indeterminate, render an animated pulse instead of a
            misleading numeric bar — the user can tell the job is alive but
            we don't fabricate a position we can't justify. */}
        {isIndeterminate ? (
          <div className="h-1.5 w-full overflow-hidden rounded-full bg-muted">
            <div className="h-full w-1/3 animate-pulse bg-primary/60" />
          </div>
        ) : (
          <Progress value={displayPct} className="h-1.5" />
        )}
      </div>
      <p aria-live="polite" className="text-xs text-muted-foreground">
        {stageDescription}
      </p>
      {/* COPY-001: data-grounded wait copy — concrete estimate that
          reframes the wait as productive (not anxiety-amplifying).
          A11Y-003: removed aria-live from elapsed span — supplementary
          info that auto-announces every second overwhelms AT users. The
          progress-percentage live region (5s polling) is sufficient. */}
      <div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground">
        <span>{waitCopy}</span>
        {elapsedLabel !== null && (
          <span data-testid="sync-elapsed">
            Running for {elapsedLabel}.
          </span>
        )}
      </div>
      <p className="text-xs text-muted-foreground">
        We&apos;re building your traffic baseline — the longer your site&apos;s
        history, the more accurate your recommendations will be.
      </p>

      {/* Server-flagged stuck state: surface a retry CTA so the user has a
          recovery action instead of refreshing the page hoping it unblocks. */}
      {isStuck && (
        <div className="mt-1 flex items-start gap-2 rounded-md border border-warning/40 bg-warning/5 p-2.5">
          <AlertTriangle className="mt-0.5 size-4 shrink-0 text-warning" aria-hidden="true" />
          <div className="flex-1 space-y-1.5">
            <p className="text-xs text-foreground">
              This sync is taking longer than usual. It may have stalled.
            </p>
            <Button
              type="button"
              size="sm"
              variant="outline"
              onClick={handleRetry}
              disabled={retrying || !siteId}
              className="h-7 gap-1.5 text-xs"
            >
              <RotateCw
                className={`h-3.5 w-3.5${retrying ? ' animate-spin' : ''}`}
                aria-hidden="true"
              />
              {retrying ? 'Restarting…' : 'Retry sync'}
            </Button>
          </div>
        </div>
      )}

      {typeof Notification !== 'undefined' && Notification.permission !== 'denied' && (
        <Button
          type="button"
          size="sm"
          variant="outline"
          onClick={requestPermissionWithFeedback}
          className="h-7 gap-1.5 text-xs"
        >
          <Bell className="size-3.5" aria-hidden="true" />
          {Notification.permission === 'granted' ? 'Notifications on' : 'Notify me when ready'}
        </Button>
      )}
      {(typeof Notification === 'undefined' || Notification.permission === 'denied') &&
        (notifSettingsHref ? (
          <a
            href={notifSettingsHref}
            className="inline-flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground underline underline-offset-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring rounded-sm"
          >
            <Bell className="size-3.5 shrink-0" aria-hidden="true" />
            Email me when ready →
          </a>
        ) : (
          <p className="text-xs text-muted-foreground flex items-center gap-1.5">
            <Bell className="size-3.5 shrink-0" aria-hidden="true" />
            Check back soon — this usually takes a few minutes.
          </p>
        ))}

      {productOverviewVideoUrl && (
        <a
          href={productOverviewVideoUrl}
          target="_blank"
          rel="noopener noreferrer"
          className="group relative mt-3 block overflow-hidden rounded-md border border-border bg-muted/40 hover:bg-muted transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
        >
          <div className="aspect-[16/9] flex items-center justify-center">
            <div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/90 text-primary-foreground shadow-sm group-hover:scale-105 transition-transform motion-reduce:transition-none">
              <PlayCircle className="size-7" aria-hidden="true" />
            </div>
          </div>
          <div className="border-t border-border/60 bg-background/60 px-3 py-2">
            <p className="text-sm font-medium text-foreground">
              While you wait — 60-second tour of RankWizAI
            </p>
            <p className="text-xs text-muted-foreground">
              See exactly what we'll show you when sync finishes.
            </p>
          </div>
        </a>
      )}
    </div>
  );
}
