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

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

import Pricing from './Pricing';

vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    Head: ({ children }: { children?: React.ReactNode }) => <head>{children}</head>,
    Link: ({ children, href }: { children: React.ReactNode; href: string }) => (
      <a href={href}>{children}</a>
    ),
    usePage: vi.fn(() => ({
      props: { auth: { user: null }, errors: {}, flash: {} },
    })),
  };
});

vi.mock('@/Components/marketing/MarketingNav', () => ({
  MarketingNav: () => <nav data-testid="marketing-nav" />,
}));

vi.mock('@/Components/marketing/MarketingFooter', () => ({
  MarketingFooter: () => <footer data-testid="marketing-footer" />,
}));

const mockTiers = {
  free: {
    name: 'Free',
    description: 'For individual bloggers',
    price: 0,
    features: ['1 WordPress site', '50 pages/run'],
  },
  pro: {
    name: 'Pro',
    description: 'For growing sites',
    price: 19,
    features: ['5 WordPress sites', 'Unlimited pages'],
  },
};

describe('Pricing — heading hierarchy (SEO-003)', () => {
  it('has exactly one h1', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );
    const h1s = container.querySelectorAll('h1');
    expect(h1s).toHaveLength(1);
  });

  it('h1 text describes the page purpose', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );
    const h1 = container.querySelector('h1');
    expect(h1?.textContent?.toLowerCase()).toContain('pricing');
  });

  it('headings do not skip from h1 to h3 (no h1→h3 jump)', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );

    // Get all headings in DOM order
    const headings = Array.from(container.querySelectorAll('h1, h2, h3, h4, h5, h6'));
    const levels = headings.map((h) => parseInt(h.tagName.slice(1), 10));

    // Verify no h3 appears before any h2 in the document
    let seenH2 = false;
    for (const level of levels) {
      if (level === 2) seenH2 = true;
      if (level === 3) {
        expect(seenH2).toBe(true);
      }
    }
  });

  it('no heading skips more than one level', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );

    const headings = Array.from(container.querySelectorAll('h1, h2, h3, h4, h5, h6'));
    const levels = headings.map((h) => parseInt(h.tagName.slice(1), 10));

    for (let i = 1; i < levels.length; i++) {
      const prev = levels[i - 1];
      const curr = levels[i];
      // A heading can go up (any decrease is fine, e.g. h3→h2)
      // A heading going down (increase) must not jump more than 1 level
      if (curr > prev) {
        expect(curr - prev).toBeLessThanOrEqual(1);
      }
    }
  });

  it('FAQ questions use h3 (not h4), under the FAQ h2', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );

    // The FAQ section h2 must exist
    const faqH2 = Array.from(container.querySelectorAll('h2')).find((h) =>
      h.textContent?.toLowerCase().includes('frequently asked'),
    );
    expect(faqH2).toBeDefined();

    // FAQ items should use h3, not h4
    const h4s = container.querySelectorAll('h4');
    expect(h4s).toHaveLength(0);

    // FAQ questions must be rendered as h3 elements (not plain text/p/strong)
    const faqH3s = container.querySelectorAll('h3');
    expect(faqH3s.length).toBeGreaterThan(0);
  });

  it('AI Drafts section uses h2 (not h3) to stay under the page h1', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );

    const aiDraftsHeading = Array.from(container.querySelectorAll('h2')).find((h) =>
      h.textContent?.toLowerCase().includes('ai drafts included'),
    );
    expect(aiDraftsHeading).toBeDefined();
  });
});

// Mocks an authenticated user for tests that need a logged-in state
const mockAuthenticatedUser = () =>
  vi.mocked(usePage).mockReturnValue({
    props: {
      auth: { user: { id: 1, name: 'Test', email: 'test@test.com' } },
      errors: {},
      flash: {},
    },
  } as unknown as ReturnType<typeof usePage>);

describe('Pricing — is_subscribed uses currentPlan (not auth.user.subscribed)', () => {
  beforeEach(() => mockAuthenticatedUser());
  afterEach(() => vi.mocked(usePage).mockReset());

  it('subscribed user (currentPlan=pro) sees Manage Billing, not upgrade CTA', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} current_plan="pro" />,
    );
    expect(container.textContent).toContain('Manage Billing');
  });

  it('free-plan user (currentPlan=free) sees upgrade CTA, not Manage Billing', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} current_plan="free" />,
    );
    expect(container.textContent).not.toContain('Manage Billing');
  });
});

describe('Pricing — lifecycle banners', () => {
  beforeEach(() => mockAuthenticatedUser());
  afterEach(() => vi.mocked(usePage).mockReset());

  it('activated banner does not appear for subscribed users', () => {
    const { container } = render(
      <Pricing
        tiers={mockTiers}
        can_login={true}
        can_register={true}
        current_plan="pro"
        lifecycle_stage="activated"
      />,
    );
    expect(container.textContent).not.toContain("You've already seen what");
  });

  it('activated banner appears for non-subscribed authenticated users', () => {
    const { container } = render(
      <Pricing
        tiers={mockTiers}
        can_login={true}
        can_register={true}
        current_plan="free"
        lifecycle_stage="activated"
      />,
    );
    expect(container.textContent).toContain("You've already seen what");
  });

  it('at_risk banner does not appear for subscribed users', () => {
    const { container } = render(
      <Pricing
        tiers={mockTiers}
        can_login={true}
        can_register={true}
        current_plan="pro"
        lifecycle_stage="at_risk"
      />,
    );
    expect(container.textContent).not.toContain("haven't logged in for a while");
  });

  it('at_risk banner appears for non-subscribed authenticated users', () => {
    const { container } = render(
      <Pricing
        tiers={mockTiers}
        can_login={true}
        can_register={true}
        current_plan="free"
        lifecycle_stage="at_risk"
      />,
    );
    expect(container.textContent).toContain("haven't logged in for a while");
  });

  it('winback banner does not appear when has_had_subscription is false', () => {
    const { container } = render(
      <Pricing
        tiers={mockTiers}
        can_login={true}
        can_register={true}
        current_plan="free"
        lifecycle_stage="winback"
        has_had_subscription={false}
      />,
    );
    expect(container.textContent).not.toContain('Reactivate your Pro plan');
  });

  it('winback banner appears when has_had_subscription is true and user is not subscribed', () => {
    const { container } = render(
      <Pricing
        tiers={mockTiers}
        can_login={true}
        can_register={true}
        current_plan="free"
        lifecycle_stage="winback"
        has_had_subscription={true}
      />,
    );
    expect(container.textContent).toContain('Reactivate your Pro plan');
  });

  it('churned banner does not appear when has_had_subscription is false', () => {
    const { container } = render(
      <Pricing
        tiers={mockTiers}
        can_login={true}
        can_register={true}
        current_plan="free"
        lifecycle_stage="churned"
        has_had_subscription={false}
      />,
    );
    expect(container.textContent).not.toContain('Reactivate your Pro plan');
  });

  it('winback banner does not appear for currently subscribed users', () => {
    const { container } = render(
      <Pricing
        tiers={mockTiers}
        can_login={true}
        can_register={true}
        current_plan="pro"
        lifecycle_stage="winback"
        has_had_subscription={true}
      />,
    );
    expect(container.textContent).not.toContain('Reactivate your Pro plan');
  });
});

describe('Pricing — free plan CTA messaging (PRICE-MSG-009)', () => {
  it('free plan CTA says "Create Free Account" (not "Start Free Analysis") to match the register action', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );

    // Free plan card CTA must use account-creation label (not analysis-implying label)
    expect(container.textContent).toContain('Create Free Account');
  });

  it('bottom CTA section uses "Create Free Account" label (not analysis-implying "Start Free Analysis")', () => {
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );

    // Use data-testid to unambiguously target the bottom CTA section
    const section = container.querySelector('[data-testid="bottom-cta-section"]');
    expect(section).toBeTruthy();

    // The section must contain 'Create Free Account', not 'Start Free Analysis'
    expect(section!.textContent).toContain('Create Free Account');
    expect(section!.textContent).not.toContain('Start Free Analysis');
  });
});

describe('Pricing — billing intent preservation (CRO-005)', () => {
  it('unauthenticated CTA links use billing_period= (not billing=) for Register.tsx compatibility', () => {
    // Register.tsx reads params.get('billing_period') and params.get('plan')
    // to set localStorage.intended_billing_period and intended_plan on mount.
    // The public pricing page must pass matching param names.
    const { container } = render(
      <Pricing tiers={mockTiers} can_login={true} can_register={true} />,
    );

    const registerLinks = Array.from(container.querySelectorAll('a[href*="register"]'));
    // There should be at least one non-free plan CTA link to register
    const paidPlanLinks = registerLinks.filter((a) => {
      const href = (a as HTMLAnchorElement).href;
      // Exclude links without plan param (e.g. bottom generic CTA)
      return href.includes('plan=');
    });

    expect(paidPlanLinks.length).toBeGreaterThan(0);

    for (const link of paidPlanLinks) {
      const href = (link as HTMLAnchorElement).href;
      // Must use billing_period= (Register.tsx reads this param name)
      expect(href).toContain('billing_period=');
      // Must NOT use billing= (old incorrect param name that Register.tsx ignores)
      expect(href).not.toMatch(/[?&]billing=[^_]/);
    }
  });
});
