import { act, fireEvent, render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';

vi.mock('@/lib/analytics', () => ({
  trackEvent: vi.fn(),
  trackProductEvent: vi.fn(),
}));

// Default: PostHog not loaded, so useExperiment returns null (no variant).
// Individual tests can override via vi.mocked(useExperiment).mockReturnValue().
vi.mock('@/hooks/useExperiment', () => ({
  useExperiment: vi.fn().mockReturnValue(null),
}));

import OnboardingWizard from './OnboardingWizard';

const baseSite = { id: 1, name: 'Test Site', domain: 'example.com', is_demo: false };

describe('OnboardingWizard', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders 3 steps visible with no connections', () => {
    render(<OnboardingWizard site={baseSite} gscConnection={null} wpConnection={null} />);

    expect(screen.getAllByText('Connect Google Search Console').length).toBeGreaterThanOrEqual(1);
    expect(screen.getAllByText('Run First Analysis').length).toBeGreaterThanOrEqual(1);
    // WordPress Plugin is a bonus step shown only after core steps are complete
  });

  it('shows completed badge for gsc step when gscConnection is present', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };

    render(<OnboardingWizard site={baseSite} gscConnection={gscConnection} wpConnection={null} />);

    // With GSC connected, step 1 should show a checkmark (aria-hidden)
    const checkIcons = document.querySelectorAll('[aria-hidden="true"]');
    expect(checkIcons.length).toBeGreaterThanOrEqual(1);
  });

  it('shows WordPress Plugin bonus step after all core steps complete', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={0}
      />,
    );

    expect(screen.getByText('WordPress Plugin')).toBeInTheDocument();
  });

  it('shows sync progress panel when gsc status is syncing', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };

    render(<OnboardingWizard site={baseSite} gscConnection={gscConnection} wpConnection={null} />);

    expect(screen.getByText('Syncing in background')).toBeInTheDocument();
  });

  it('strips https:// scheme from domain in sample preview URL', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };
    const siteWithScheme = { ...baseSite, domain: 'https://example.com' };

    render(
      <OnboardingWizard site={siteWithScheme} gscConnection={gscConnection} wpConnection={null} />,
    );

    expect(screen.getByText(/https:\/\/example\.com\/blog\/your-first-post/)).toBeInTheDocument();
    expect(screen.queryByText(/https:\/\/https:\/\//)).not.toBeInTheDocument();
  });

  it('shows step 1 of 3 when no connections', () => {
    render(<OnboardingWizard site={baseSite} gscConnection={null} wpConnection={null} />);

    expect(screen.getByText('Step 1 of 3')).toBeInTheDocument();
  });

  it('shows plugin install helper toggle when wp is not connected after steps complete', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={0}
      />,
    );

    expect(screen.getByText('Need to install the plugin first?')).toBeInTheDocument();
  });

  it('reveals download button when plugin install helper is expanded', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={0}
      />,
    );

    const toggle = screen.getByText('Need to install the plugin first?');
    fireEvent.click(toggle.closest('button')!);

    expect(screen.getByText('Download Plugin')).toBeInTheDocument();
  });

  it('marks analysis step completed when latestRun status is completed', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
      />,
    );

    // With GSC + analysis completed, steps 1 and 3 should have check marks
    const checkIcons = document.querySelectorAll('[aria-hidden="true"]');
    expect(checkIcons.length).toBeGreaterThanOrEqual(2);
  });

  it('shows optional WP step hint when wp is not connected after steps complete (ACT-002)', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={0}
      />,
    );
    // WP step is now a bonus step shown after core steps — Optional hint is shown
    expect(screen.getByText(/Optional — do this later from Site Settings/)).toBeInTheDocument();
  });

  // ACT-008: Referral nudge in sync-wait card

  it('shows referral copy block inside sync-wait card when isSyncing and referralUrl is present', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        referralUrl="https://rankwiz.app/?ref=abc123"
      />,
    );

    expect(screen.getByText(/Know someone who needs SEO insights/)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: 'Copy referral link' })).toBeInTheDocument();
  });

  it('does not show referral copy block when referralUrl is null', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        referralUrl={null}
      />,
    );

    expect(screen.queryByText(/Know someone who needs SEO insights/)).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'Copy referral link' })).not.toBeInTheDocument();
  });

  it('does not show referral copy block when not syncing even with referralUrl', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        referralUrl="https://rankwiz.app/?ref=abc123"
      />,
    );

    // Not syncing (no gsc connection), so exploration card is not shown
    expect(screen.queryByText(/Know someone who needs SEO insights/)).not.toBeInTheDocument();
  });

  it('shows post-analysis nudge when analysis completed and wp not connected (ACT-002)', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
      />,
    );

    // Post-analysis: AI draft nudge is shown
    expect(
      screen.getByText('Generate your first AI draft to complete activation'),
    ).toBeInTheDocument();
  });

  // ACT-011: Data coverage warning tests
  const syncedGscConnection = {
    property_url: 'sc-domain:example.com',
    last_synced_at: '2025-01-01T00:00:00.000Z',
    status: 'synced',
  };

  it('shows data coverage warning when coverage_days < 56 and status is synced', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={syncedGscConnection}
        wpConnection={null}
        gscDataRange={{ earliest: '2025-01-01', latest: '2025-01-20', coverage_days: 19 }}
      />,
    );

    expect(screen.getByRole('alert')).toBeInTheDocument();
    expect(screen.getByText(/19 day/)).toBeInTheDocument();
    expect(screen.getByText(/Limited data/)).toBeInTheDocument();
  });

  it('does not show data coverage warning when coverage_days >= 56', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={syncedGscConnection}
        wpConnection={null}
        gscDataRange={{ earliest: '2024-11-01', latest: '2025-01-01', coverage_days: 61 }}
      />,
    );

    expect(screen.queryByRole('alert')).not.toBeInTheDocument();
  });

  it('still renders Analyze Now CTA when coverage warning is shown (non-blocking)', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={syncedGscConnection}
        wpConnection={null}
        gscDataRange={{ earliest: '2025-01-01', latest: '2025-01-20', coverage_days: 19 }}
      />,
    );

    expect(screen.getByRole('alert')).toBeInTheDocument();
    expect(screen.getByText('Analyze Now')).toBeInTheDocument();
  });

  it('does not show warning when coverage_days is null', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={syncedGscConnection}
        wpConnection={null}
        gscDataRange={{ earliest: null, latest: null, coverage_days: null }}
      />,
    );

    expect(screen.queryByRole('alert')).not.toBeInTheDocument();
  });

  // ACT-002: DraftOutputTeaser visibility tests
  const completedLatestRun = {
    id: 1,
    status: 'completed',
    before_start: null,
    before_end: null,
    after_start: null,
    after_end: null,
    summary: null,
  };

  it('shows DraftOutputTeaser when analysis completed and bundledRemaining is null (BYOK-only mode)', () => {
    // Default usePage mock has no ai_status → bundledRemaining === null → teaser shown
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={syncedGscConnection}
        wpConnection={null}
        latestRun={completedLatestRun}
      />,
    );

    expect(screen.getByTestId('draft-output-teaser')).toBeInTheDocument();
  });

  it('shows DraftOutputTeaser when analysis completed and bundledRemaining is 0 (credits exhausted)', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue({
      props: {
        auth: { user: null },
        errors: {},
        flash: {},
        polling_interval_ms: 5000,
        ai_status: { bundled_remaining: 0 },
      },
    } as unknown as ReturnType<typeof usePage>);

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={syncedGscConnection}
        wpConnection={null}
        latestRun={completedLatestRun}
      />,
    );

    expect(screen.getByTestId('draft-output-teaser')).toBeInTheDocument();

    vi.mocked(usePage).mockRestore();
  });

  // ACT-003: Healthy site card (0 recommendations after completed analysis)

  it('renders healthy-site card when analysis is completed and recommendationsCount is 0', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={0}
      />,
    );

    expect(
      screen.getByText('Your site looks healthy — no urgent issues found in your GSC data.'),
    ).toBeInTheDocument();
    expect(screen.getByText('Keyword Opportunities')).toBeInTheDocument();
    expect(screen.getByText('Topic Clusters')).toBeInTheDocument();
    expect(screen.getByText('Content Freshness')).toBeInTheDocument();
  });

  it('does not render healthy-site card when recommendationsCount is positive', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={5}
      />,
    );

    expect(
      screen.queryByText('Your site looks healthy — no urgent issues found in your GSC data.'),
    ).not.toBeInTheDocument();
  });

  it('fires GSC_SYNC_ESCAPE with numeric wait_time_ms when "Go to Dashboard" is clicked during sync', async () => {
    const { trackEvent } = await import('@/lib/analytics');
    vi.mocked(trackEvent).mockClear();

    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };

    render(<OnboardingWizard site={baseSite} gscConnection={gscConnection} wpConnection={null} />);

    const dashboardBtn = screen.getByRole('button', { name: 'Go to Dashboard' });
    fireEvent.click(dashboardBtn);

    expect(vi.mocked(trackEvent)).toHaveBeenCalledWith(
      'gsc_sync_escape',
      expect.objectContaining({ wait_time_ms: expect.any(Number) }),
    );
  });

  it('keeps the sync escape CTA disabled only after successful dashboard navigation', async () => {
    const { trackEvent } = await import('@/lib/analytics');
    const { router } = await import('@inertiajs/react');

    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };

    const { unmount } = render(
      <OnboardingWizard site={baseSite} gscConnection={gscConnection} wpConnection={null} />,
    );

    vi.mocked(trackEvent).mockClear();

    const dashboardBtn = screen.getByRole('button', { name: 'Go to Dashboard' });
    fireEvent.click(dashboardBtn);

    expect(dashboardBtn).toBeDisabled();

    const visitOptions = vi.mocked(router.visit).mock.calls.at(-1)?.[1] as {
      onSuccess?: () => void;
      onFinish?: () => void;
    };

    expect(visitOptions).toEqual(
      expect.objectContaining({
        onSuccess: expect.any(Function),
        onFinish: expect.any(Function),
      }),
    );

    act(() => {
      visitOptions.onSuccess?.();
      visitOptions.onFinish?.();
    });

    fireEvent.click(dashboardBtn);
    expect(vi.mocked(router.visit)).toHaveBeenCalledTimes(1);

    unmount();
    expect(vi.mocked(trackEvent)).not.toHaveBeenCalledWith(
      'onboarding_abandoned',
      expect.any(Object),
    );
  });

  it('re-enables the sync escape CTA when dashboard navigation does not complete', async () => {
    const { trackEvent } = await import('@/lib/analytics');
    const { router } = await import('@inertiajs/react');

    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };

    const { unmount } = render(
      <OnboardingWizard site={baseSite} gscConnection={gscConnection} wpConnection={null} />,
    );

    vi.mocked(trackEvent).mockClear();

    const dashboardBtn = screen.getByRole('button', { name: 'Go to Dashboard' });
    fireEvent.click(dashboardBtn);

    expect(dashboardBtn).toBeDisabled();

    const visitOptions = vi.mocked(router.visit).mock.calls.at(-1)?.[1] as {
      onFinish?: () => void;
    };

    act(() => {
      visitOptions.onFinish?.();
    });

    expect(dashboardBtn).not.toBeDisabled();

    unmount();
    expect(vi.mocked(trackEvent)).toHaveBeenCalledWith(
      'onboarding_abandoned',
      expect.objectContaining({ was_syncing: true }),
    );
  });

  it('shows notification settings link when siteId present and route() succeeds during syncing', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };

    const origNotification = globalThis.Notification;
    Object.defineProperty(globalThis, 'Notification', {
      value: { permission: 'denied' },
      writable: true,
      configurable: true,
    });

    try {
      render(
        <OnboardingWizard
          site={{ ...baseSite, id: 42 }}
          gscConnection={gscConnection}
          wpConnection={null}
        />,
      );

      expect(screen.getByText('Email me when ready →')).toBeInTheDocument();
    } finally {
      Object.defineProperty(globalThis, 'Notification', {
        value: origNotification,
        writable: true,
        configurable: true,
      });
    }
  });

  it('shows fallback paragraph when route() throws for notification-settings during syncing', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: null,
      status: 'syncing',
    };

    const origNotification = globalThis.Notification;
    Object.defineProperty(globalThis, 'Notification', {
      value: { permission: 'denied' },
      writable: true,
      configurable: true,
    });

    const origRoute = (globalThis as unknown as { route: (name: string) => string }).route;
    (globalThis as unknown as { route: (name: string) => string }).route = (name: string) => {
      if (name === 'notification-settings.show') throw new Error('Route not found');
      return origRoute(name);
    };

    try {
      render(
        <OnboardingWizard
          site={{ ...baseSite, id: 42 }}
          gscConnection={gscConnection}
          wpConnection={null}
        />,
      );

      expect(screen.queryByText('Email me when ready →')).not.toBeInTheDocument();
      expect(
        screen.getByText('Check back soon — this usually takes a few minutes.'),
      ).toBeInTheDocument();
    } finally {
      (globalThis as unknown as { route: (name: string) => string }).route = origRoute;
      Object.defineProperty(globalThis, 'Notification', {
        value: origNotification,
        writable: true,
        configurable: true,
      });
    }
  });

  it('counts step3 as complete and shows step 3 of 3 when analysisCompleted with 0 recs', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={0}
      />,
    );

    // All 3 steps complete: gsc(1) + analysis(1) + healthy(1) = 3
    // currentStep = min(3+1, 3) = 3, so "Step 3 of 3"
    expect(screen.getByText('Step 3 of 3')).toBeInTheDocument();
  });

  // ACT-003: Persona-based messaging tests

  it('shows generic analysis description when userRole is not provided', () => {
    render(<OnboardingWizard site={baseSite} gscConnection={null} wpConnection={null} />);
    expect(
      screen.getByText('Analyze your GSC data to surface SEO opportunities and recommendations.'),
    ).toBeInTheDocument();
  });

  it('shows blogger-specific analysis description when userRole is blogger', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        userRole="blogger"
      />,
    );
    expect(
      screen.getByText(/AI-powered rewrite suggestions for your highest-traffic pages/),
    ).toBeInTheDocument();
  });

  it('shows agency-specific analysis description when userRole is agency_owner', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        userRole="agency_owner"
      />,
    );
    expect(screen.getByText(/team-ready action plans and shareable reports/)).toBeInTheDocument();
  });

  it('shows ecommerce-specific analysis description when userRole is ecommerce_manager', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        userRole="ecommerce_manager"
      />,
    );
    expect(screen.getByText(/product page and category SEO opportunities/)).toBeInTheDocument();
  });

  it('includes user_role in ONBOARDING_COMPLETED event when userRole is provided', async () => {
    const { trackProductEvent } = await import('@/lib/analytics');
    vi.mocked(trackProductEvent).mockClear();

    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={0}
        userRole="blogger"
      />,
    );

    expect(vi.mocked(trackProductEvent)).toHaveBeenCalledWith(
      'onboarding_completed',
      expect.objectContaining({ user_role: 'blogger' }),
    );
  });

  // ACT-002: A/B test — demo placement experiment tests

  it('shows demo CTA inside GSC card (control path) when demoDataAvailable and no variant', () => {
    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        demoDataAvailable={true}
      />,
    );
    // With no PostHog variant (null), demo CTA should appear inside the GSC card
    expect(screen.getAllByText('Explore with sample data').length).toBeGreaterThanOrEqual(1);
  });

  it('shows early demo card above GSC card when variant_a is active', async () => {
    const { useExperiment } = await import('@/hooks/useExperiment');
    vi.mocked(useExperiment).mockReturnValue('variant_a');

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        demoDataAvailable={true}
      />,
    );

    expect(screen.getByText('See RankWiz in action instantly')).toBeInTheDocument();
    expect(screen.getByText(/Not ready to connect GSC yet\?/)).toBeInTheDocument();

    vi.mocked(useExperiment).mockReset();
  });

  it('hides demo CTA from inside GSC card when variant_a is active', async () => {
    const { useExperiment } = await import('@/hooks/useExperiment');
    vi.mocked(useExperiment).mockReturnValue('variant_a');

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        demoDataAvailable={true}
      />,
    );

    // The early demo card renders one "Explore with sample data" button.
    // The GSC card in-line version should be absent.
    const exploreBtns = screen.getAllByText('Explore with sample data');
    // Only the early card version is shown; no "or" divider inside GSC card
    expect(screen.queryByText('or')).not.toBeInTheDocument();
    expect(exploreBtns).toHaveLength(1);

    vi.mocked(useExperiment).mockReset();
  });

  // ACT-002: experiment variant tracked in ONBOARDING_STEP_VIEWED
  it('includes experiment_demo_variant in ONBOARDING_STEP_VIEWED when variant is active', async () => {
    const { useExperiment } = await import('@/hooks/useExperiment');
    vi.mocked(useExperiment).mockReturnValue('variant_a');

    const { trackProductEvent } = await import('@/lib/analytics');
    vi.mocked(trackProductEvent).mockClear();

    render(<OnboardingWizard site={baseSite} gscConnection={null} wpConnection={null} />);

    const calls = vi.mocked(trackProductEvent).mock.calls.filter(
      ([event]) => event === 'onboarding_step_viewed',
    );
    expect(calls.length).toBeGreaterThan(0);
    calls.forEach(([, props]) => {
      expect(props).toEqual(expect.objectContaining({ experiment_demo_variant: 'variant_a' }));
    });

    vi.mocked(useExperiment).mockReset();
  });

  it('omits experiment_demo_variant from ONBOARDING_STEP_VIEWED when no variant (null)', async () => {
    const { useExperiment } = await import('@/hooks/useExperiment');
    vi.mocked(useExperiment).mockReturnValue(null);

    const { trackProductEvent } = await import('@/lib/analytics');
    vi.mocked(trackProductEvent).mockClear();

    render(<OnboardingWizard site={baseSite} gscConnection={null} wpConnection={null} />);

    const calls = vi.mocked(trackProductEvent).mock.calls.filter(
      ([event]) => event === 'onboarding_step_viewed',
    );
    calls.forEach(([, props]) => {
      expect(props).not.toHaveProperty('experiment_demo_variant');
    });

    vi.mocked(useExperiment).mockReset();
  });

  // ACT-003: user_role tracked in ONBOARDING_STEP_VIEWED
  it('includes user_role in ONBOARDING_STEP_VIEWED when userRole prop is provided', async () => {
    const { trackProductEvent } = await import('@/lib/analytics');
    vi.mocked(trackProductEvent).mockClear();

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        userRole="agency_owner"
      />,
    );

    expect(vi.mocked(trackProductEvent)).toHaveBeenCalledWith(
      'onboarding_step_viewed',
      expect.objectContaining({ user_role: 'agency_owner' }),
    );
  });

  it('omits user_role from ONBOARDING_STEP_VIEWED when userRole prop is null', async () => {
    const { trackProductEvent } = await import('@/lib/analytics');
    vi.mocked(trackProductEvent).mockClear();

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={null}
        wpConnection={null}
        userRole={null}
      />,
    );

    const calls = vi.mocked(trackProductEvent).mock.calls.filter(
      ([event]) => event === 'onboarding_step_viewed',
    );
    calls.forEach(([, props]) => {
      expect(props).not.toHaveProperty('user_role');
    });
  });

  // ACT-007: "See Your Recommendations" CTA after analysis completes

  it('shows See Your Recommendations CTA when analysis completed and recommendationsCount > 0', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={5}
      />,
    );

    expect(screen.getByText('See Your Recommendations')).toBeInTheDocument();
    expect(screen.getByText('Your recommendations are ready')).toBeInTheDocument();
    expect(screen.getByText(/5 recommendations found/)).toBeInTheDocument();
  });

  it('does not show See Your Recommendations CTA when analysis completed but recommendationsCount is 0', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={0}
      />,
    );

    expect(screen.queryByText('See Your Recommendations')).not.toBeInTheDocument();
  });

  it('does not show See Your Recommendations CTA when analysis has not completed', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        recommendationsCount={5}
      />,
    );

    expect(screen.queryByText('See Your Recommendations')).not.toBeInTheDocument();
  });

  it('does not show See Your Recommendations CTA when analysis is running with stale recommendationsCount > 0', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'running',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={5}
      />,
    );

    expect(screen.queryByText('See Your Recommendations')).not.toBeInTheDocument();
  });

  it('fires WIZARD_SEE_RECOMMENDATIONS_CLICKED when See Your Recommendations CTA is clicked', async () => {
    const { trackEvent } = await import('@/lib/analytics');
    vi.mocked(trackEvent).mockClear();

    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={3}
      />,
    );

    const cta = screen.getByRole('link', { name: /See Your Recommendations/i });
    fireEvent.click(cta);

    expect(vi.mocked(trackEvent)).toHaveBeenCalledWith(
      'wizard_see_recommendations_clicked',
      expect.objectContaining({
        site_id: '1',
        recommendations_count: '3',
      }),
    );
  });

  it('See Your Recommendations CTA link includes from=wizard query param', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={7}
      />,
    );

    const link = screen.getByRole('link', { name: /See Your Recommendations/i });
    expect(link).toHaveAttribute('href', expect.stringContaining('from=wizard'));
  });

  it('shows singular "1 recommendation found" when recommendationsCount is 1', () => {
    const gscConnection = {
      property_url: 'sc-domain:example.com',
      last_synced_at: '2025-01-01T00:00:00.000Z',
      status: 'synced',
    };
    const latestRun = {
      id: 1,
      status: 'completed',
      before_start: null,
      before_end: null,
      after_start: null,
      after_end: null,
      summary: null,
    };

    render(
      <OnboardingWizard
        site={baseSite}
        gscConnection={gscConnection}
        wpConnection={null}
        latestRun={latestRun}
        recommendationsCount={1}
      />,
    );

    expect(screen.getByText(/1 recommendation found/)).toBeInTheDocument();
    expect(screen.queryByText(/1 recommendations found/)).not.toBeInTheDocument();
  });
});
