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

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

import { trackEvent } from '@/lib/analytics';
import { BYOK_LINK_CLICKED } from '@/lib/event-catalog';
import type { PageProps } from '@/types';

import { AiDraftNudgeCard } from './AiDraftNudgeCard';

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

// DraftOutputTeaser is only rendered on the exhausted branches; stub it so those
// tests don't depend on its internals (it has its own coverage).
vi.mock('@/Components/Ai/DraftOutputTeaser', () => ({
  DraftOutputTeaser: () => <div data-testid="draft-output-teaser" />,
}));

const mockedUsePage = vi.mocked(usePage);
const mockedTrackEvent = vi.mocked(trackEvent);

/**
 * Build a minimal usePage().props payload. AiDraftNudgeCard reads trial, plan,
 * and features; cast through unknown so we don't satisfy the full PageProps surface.
 */
function mockProps(overrides: {
  plan?: string | null;
  trialActive?: boolean;
  billing?: boolean;
} = {}) {
  const { plan = null, trialActive = false, billing = true } = overrides;
  mockedUsePage.mockReturnValue({
    props: {
      plan,
      trial: { active: trialActive },
      features: { billing },
    },
  } as unknown as ReturnType<typeof usePage<PageProps>>);
}

describe('AiDraftNudgeCard', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    localStorage.clear();
  });

  it('renders the bundled no-key happy path when credits remain (ONBOARD-002)', () => {
    // P0-3 gap backfill: the positive bundled-credit branch — "no API key needed"
    // CTA into the recommendations page — was previously untested.
    mockProps({ plan: 'pro' });
    render(<AiDraftNudgeCard siteId={'42'} bundledRemaining={5} />);

    expect(screen.getByText(/5 bundled AI drafts/i)).toBeInTheDocument();
    // ONBOARD-002: contextualized count — "enough for N recommendation rewrites"
    expect(screen.getByText(/enough for 5 recommendation rewrites/i)).toBeInTheDocument();
    expect(screen.getByText(/no API key needed/i)).toBeInTheDocument();

    const cta = screen.getByRole('link', { name: /generate your first ai draft/i });
    expect(cta).toHaveAttribute('href', '/sites/42/recommendations');
    // The no-key path must NOT surface the BYOK fallback teaser.
    expect(screen.queryByTestId('draft-output-teaser')).not.toBeInTheDocument();
  });

  it('singularizes the credit count and rewrite label when exactly one bundled draft remains', () => {
    mockProps({ plan: 'pro' });
    render(<AiDraftNudgeCard siteId={'7'} bundledRemaining={1} />);

    expect(screen.getByText(/1 bundled AI draft\b/i)).toBeInTheDocument();
    expect(screen.queryByText(/bundled AI drafts/i)).not.toBeInTheDocument();
    // Singular "rewrite" not "rewrites"
    expect(screen.getByText(/enough for 1 recommendation rewrite\b/i)).toBeInTheDocument();
    expect(screen.queryByText(/recommendation rewrites/i)).not.toBeInTheDocument();
  });

  it('shows the upgrade CTA (not the no-key path) for a free user out of credits', () => {
    mockProps({ plan: null, trialActive: false, billing: true });
    render(<AiDraftNudgeCard siteId={'9'} bundledRemaining={0} />);

    expect(
      screen.getByRole('link', { name: /upgrade to pro — 14-day free trial/i }),
    ).toBeInTheDocument();
    expect(screen.queryByText(/no API key needed/i)).not.toBeInTheDocument();
  });

  it('shows the BYOK fallback for a Pro user out of credits and fires the funnel event', () => {
    mockProps({ plan: 'pro', trialActive: false, billing: true });
    render(<AiDraftNudgeCard siteId={'11'} bundledRemaining={0} />);

    const cta = screen.getByRole('link', { name: /unlock full ai drafts/i });
    expect(cta).toHaveAttribute('href', '/settings/ai');

    cta.click();
    expect(mockedTrackEvent).toHaveBeenCalledWith(
      BYOK_LINK_CLICKED,
      expect.objectContaining({ site_id: '11', plan_tier: 'pro', source: 'byok_only_fallback' }),
    );
  });
});
