/**
 * DashboardBanners — banner builder for the Dashboard page (DEBT-005 extraction).
 *
 * Returns the BannerEntry[] array for BannerStack. All dismiss state is managed
 * here via a custom hook so Dashboard.tsx holds no banner-specific useState calls.
 *
 * Priority ladder (high → low): connection > billing > setup > nudge.
 * See M4 spec for the priority-collapse behaviour (BannerStack tests it).
 */
import { AlertTriangle, Bell, Flame, Rocket, X } from 'lucide-react';

import { useState } from 'react';

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

import { type BannerEntry } from '@/Components/Dashboard/BannerStack';
import { Alert, AlertDescription, AlertTitle } from '@/Components/ui/alert';
import { Button } from '@/Components/ui/button';
import { trackEvent } from '@/lib/analytics';
import { SYNC_ESTIMATE_COPY } from '@/lib/copy/gsc';
import { ONBOARDING_RESUME_CLICKED } from '@/lib/event-catalog';

/* ─── types ──────────────────────────────────────────────────────────────── */

interface GscExpiringConnection {
  site_id: string;
  site_name: string;
  expires_at: string;
  days_until_expiry: number;
}

/** INTUX-101: WP connection in a degraded (auth_failed / unreachable) state. */
interface WpDegradedConnection {
  site_id: string;
  site_name: string;
  status: 'auth_failed' | 'unreachable';
}

interface BannerMetrics {
  pending_recommendations: number;
  latest_analysis_at: string | null;
}

export interface UseDashboardBannersOptions {
  userId: number | undefined;
  firstSite: { id: string; name: string } | null | undefined;
  gscSyncing: boolean;
  gscConnectedNoRun: boolean;
  gscExpiringConnections: GscExpiringConnection[];
  /** INTUX-101: WP connections in auth_failed / unreachable state needing recovery. */
  wpDegradedConnections?: WpDegradedConnection[];
  wizardCompleted: boolean;
  isActivated: boolean;
  hasReviewedRecommendation: boolean;
  onboardingFeatureEnabled: boolean;
  streakMilestoneNotification: { id: string; weeks: number } | null;
  dashboardMetrics: BannerMetrics | null | undefined;
  requestSyncNotificationPermission: () => void;
}

/* ─── hook ───────────────────────────────────────────────────────────────── */

export function useDashboardBanners({
  userId,
  firstSite,
  gscSyncing,
  gscConnectedNoRun,
  gscExpiringConnections,
  wpDegradedConnections = [],
  wizardCompleted,
  isActivated,
  hasReviewedRecommendation: _hasReviewedRecommendation,
  onboardingFeatureEnabled,
  streakMilestoneNotification,
  dashboardMetrics: _dashboardMetrics,
  requestSyncNotificationPermission,
}: UseDashboardBannersOptions): BannerEntry[] {
  const [onboardingBannerDismissed, setOnboardingBannerDismissed] = useState(() => {
    try {
      return localStorage.getItem(`onboarding_banner_dismissed_${userId}`) === '1';
    } catch {
      return false;
    }
  });

  const dismissOnboardingBanner = () => {
    try {
      localStorage.setItem(`onboarding_banner_dismissed_${userId}`, '1');
    } catch {
      // ignore storage errors
    }
    setOnboardingBannerDismissed(true);
  };

  const [streakMilestoneDismissed, setStreakMilestoneDismissed] = useState(() => {
    if (!streakMilestoneNotification) return true;
    try {
      return (
        localStorage.getItem(`streak_milestone_dismissed_${streakMilestoneNotification.id}`) === '1'
      );
    } catch {
      return false;
    }
  });

  const dismissStreakMilestoneBanner = () => {
    if (streakMilestoneNotification) {
      try {
        localStorage.setItem(
          `streak_milestone_dismissed_${streakMilestoneNotification.id}`,
          '1',
        );
      } catch {
        // ignore storage errors
      }
    }
    setStreakMilestoneDismissed(true);
  };

  const banners: BannerEntry[] = [];

  // CRO-003: GSC sync-in-progress (connection)
  if (gscSyncing && firstSite) {
    banners.push({
      key: 'gsc-syncing',
      priority: 'connection',
      render: () => (
        <Alert className="mb-6 border-primary/40 bg-primary/5">
          <Rocket className="size-5 text-primary" />
          <AlertTitle className="text-base font-semibold flex items-center gap-2">
            <span className="live-dot" aria-hidden="true" />
            {`Your GSC data is syncing — ${SYNC_ESTIMATE_COPY}`}
          </AlertTitle>
          <AlertDescription className="mt-1 flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-4">
            {/* P2-12: set a concrete wait-time expectation and tell the user the
                first analysis runs automatically on sync-complete (wired in
                GscSyncService → AutomationOrchestrationService::afterSyncCompleted),
                so they don't sit waiting for a manual "Run analysis" button.
                UX-207: estimate now sourced from SYNC_ESTIMATE_COPY constant. */}
            <span className="text-muted-foreground text-sm">
              Your first analysis starts automatically when sync finishes — we&apos;ll notify you
              the moment your results are ready. Feel free to explore in the meantime.
            </span>
            {typeof Notification !== 'undefined' && Notification.permission !== 'denied' && (
              <button
                type="button"
                onClick={requestSyncNotificationPermission}
                className="inline-flex shrink-0 items-center gap-1.5 rounded-md border border-primary/40 bg-background px-3 py-1.5 text-xs font-medium text-primary hover:bg-primary/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring transition-colors"
              >
                <Bell className="size-3.5" aria-hidden="true" />
                {Notification.permission === 'granted'
                  ? 'Notifications on'
                  : 'Notify me when ready'}
              </button>
            )}
          </AlertDescription>
        </Alert>
      ),
    });
  }

  // GSC connection expiry warnings (connection)
  if (gscExpiringConnections.length > 0) {
    banners.push({
      key: 'gsc-expiring',
      priority: 'connection',
      render: () => (
        <div className="mb-6 space-y-2">
          {gscExpiringConnections.map((connection) => (
            <Alert key={connection.site_id} className="border-warning/30 bg-warning/5">
              <Rocket className="size-5 text-warning" />
              <AlertTitle className="text-sm font-semibold">
                Google Search Console Connection Expires Soon
              </AlertTitle>
              <AlertDescription className="text-sm mt-1">
                Your GSC connection for <strong>{connection.site_name}</strong> expires in{' '}
                <span className="font-data">
                  {connection.days_until_expiry} day{connection.days_until_expiry !== 1 ? 's' : ''}
                </span>
                . Re-authenticate to avoid data gaps.
                {firstSite && (
                  <Button asChild size="sm" variant="outline" className="ml-3 mt-2 inline-flex">
                    <Link href={route('onboarding.index', connection.site_id)}>Reconnect GSC</Link>
                  </Button>
                )}
              </AlertDescription>
            </Alert>
          ))}
        </div>
      ),
    });
  }

  // INTUX-101: WP auth_failed / unreachable recovery banners (connection priority).
  // A broken WP connection disables AI draft publishing — surface it prominently.
  if (wpDegradedConnections.length > 0) {
    banners.push({
      key: 'wp-degraded',
      priority: 'connection',
      render: () => (
        <div className="mb-6 space-y-2">
          {wpDegradedConnections.map((conn) => (
            <Alert key={conn.site_id} className="border-destructive/30 bg-destructive/5">
              <AlertTriangle className="size-5 text-destructive" />
              <AlertTitle className="text-sm font-semibold text-destructive">
                WordPress connection broken — {conn.site_name}
              </AlertTitle>
              <AlertDescription className="text-sm mt-1">
                {conn.status === 'auth_failed'
                  ? 'Authentication failed. AI draft publishing is disabled until you reconnect.'
                  : 'The WordPress site is unreachable. AI draft publishing is disabled.'}
                {firstSite && (
                  <Button asChild size="sm" variant="default" className="ml-3 mt-2 inline-flex">
                    <Link href={route('onboarding.index', conn.site_id)}>Reconnect WordPress</Link>
                  </Button>
                )}
              </AlertDescription>
            </Alert>
          ))}
        </div>
      ),
    });
  }

  // ACT-008: Resume Onboarding (setup)
  if (
    onboardingFeatureEnabled &&
    !wizardCompleted &&
    !gscConnectedNoRun &&
    firstSite &&
    !onboardingBannerDismissed
  ) {
    banners.push({
      key: 'onboarding-resume',
      priority: 'setup',
      render: () => (
        <Alert className="mb-6 border-primary/60 bg-primary/10 relative">
          <Rocket className="size-6 text-primary" />
          <AlertTitle className="text-xl font-bold">Your SEO data is waiting</AlertTitle>
          <AlertDescription className="mt-2">
            <p className="mb-3 text-muted-foreground">
              Finish setup to see which pages are losing traffic, where you&apos;re close to
              ranking, and get AI-written fixes ready to publish — in minutes.
            </p>
            <Button asChild>
              <Link href={`/sites/${firstSite.id}/onboarding`}>Resume Onboarding</Link>
            </Button>
          </AlertDescription>
          <button
            onClick={dismissOnboardingBanner}
            className="absolute top-3 right-3 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
            aria-label="Dismiss onboarding banner"
          >
            <X className="size-4" />
          </button>
        </Alert>
      ),
    });
  }

  // UI-009: Step-2 banner (setup) — non-dismissable so users can't skip the "run
  // your first analysis" gate. The dismiss state is preserved in props/server for
  // backwards compat but the banner is no longer gated on it.
  if (gscConnectedNoRun && firstSite) {
    banners.push({
      key: 'step-2-banner',
      priority: 'setup',
      render: () => (
        <Alert className="mb-6 border-primary/50 bg-primary/5">
          <Rocket className="size-5 text-primary" />
          <AlertTitle className="text-lg font-semibold">
            Step 2 of 3 — Run Your First Analysis
          </AlertTitle>
          <AlertDescription className="mt-2">
            <p className="mb-3 text-muted-foreground">
              Your Google Search Console is connected. Run your first analysis to see which pages
              are worth fixing — takes about 30 seconds.
            </p>
            <Button asChild>
              <Link
                href={`/sites/${firstSite.id}/onboarding`}
                onClick={() =>
                  trackEvent(ONBOARDING_RESUME_CLICKED, {
                    site_id: String(firstSite.id),
                    step: '2',
                    step_name: 'analysis',
                    source: 'dashboard_banner',
                  })
                }
              >
                Continue Setup
              </Link>
            </Button>
          </AlertDescription>
        </Alert>
      ),
    });
  }

  // ACT-008: Post-wizard pre-activation (setup)
  if (wizardCompleted && !isActivated && !gscConnectedNoRun && firstSite) {
    banners.push({
      key: 'post-wizard-pre-activation',
      priority: 'setup',
      render: () => (
        <Alert className="mb-6 border-primary/50 bg-primary/5">
          <Rocket className="size-5 text-primary" />
          <AlertTitle className="text-lg font-semibold">Run Your First Analysis</AlertTitle>
          <AlertDescription className="mt-2">
            <p className="mb-3 text-muted-foreground">
              Your setup is complete. Run your first analysis to surface SEO opportunities and get
              actionable recommendations for your site.
            </p>
            <Button asChild>
              <Link href={route('analyze.index', firstSite.id)}>Run Analysis Now</Link>
            </Button>
          </AlertDescription>
        </Alert>
      ),
    });
  }

  /* RET-005: Streak milestone (nudge) — toned down from celebratory banner.
     No social share CTA. What stays:
     a small editorial alert acknowledging the milestone. The tests still
     assert on the "X-Week SEO Streak" text so we keep that label intact. */
  if (streakMilestoneNotification && !streakMilestoneDismissed) {
    banners.push({
      key: `streak-milestone-${streakMilestoneNotification.id}`,
      priority: 'nudge',
      render: () => (
        <Alert className="mb-6 border-warning/30 bg-warning/5 relative">
          <Flame className="size-5 text-warning-strong" />
          <AlertTitle className="text-base font-semibold">
            {streakMilestoneNotification.weeks}-Week SEO Streak
          </AlertTitle>
          <AlertDescription className="mt-1.5">
            <p className="text-sm text-muted-foreground">
              You&apos;ve maintained{' '}
              <span className="font-data font-semibold text-foreground">
                {streakMilestoneNotification.weeks} consecutive weeks
              </span>{' '}
              of analysis. Consistency compounds.
            </p>
          </AlertDescription>
          <button
            onClick={dismissStreakMilestoneBanner}
            className="absolute top-3 right-3 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
            aria-label="Dismiss streak milestone"
          >
            <X className="size-4" />
          </button>
        </Alert>
      ),
    });
  }

  // UX-205: Results-ready banner removed — PayoffHero (Dashboard.tsx) is the canonical
  // first-results surface. Showing both creates a four-stacked-CTA pileup above the fold.
  // The metric tile link still reads as data, providing ambient awareness.

  return banners;
}
