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

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

import type { PageProps } from '@/types';

import Pricing from './Pricing';

interface TierConfig {
  name: string;
  description: string;
  price: number | null;
  price_annual?: number | null;
  stripe_price_id?: string | null;
  stripe_price_id_annual?: string | null;
  per_seat?: boolean;
  min_seats?: number | null;
  coming_soon?: boolean;
  contact_only?: boolean;
  limits?: Record<string, number | null>;
  features?: string[];
}

vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    usePage: vi.fn(() => ({
      props: {
        auth: { user: null },
        features: {
          billing: true,
          apiTokens: false,
          userSettings: false,
          webhooks: false,
          notifications: false,
          socialAuth: false,
          twoFactor: false,
          emailVerification: true,
          onboarding: false,
          apiDocs: false,
          admin: false,
        },
        tiers: {},
        current_plan: null,
        trial: null,
        trialEnabled: false,
        trialDays: 14,
      },
    })),
    router: {
      visit: vi.fn(),
      post: vi.fn(),
    },
    Head: ({ title }: { title: string }) => <title>{title}</title>,
    Link: ({ children, href }: { children: React.ReactNode; href: string }) => (
      <a href={href}>{children}</a>
    ),
  };
});

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

vi.mock('@/Layouts/DashboardLayout', () => ({
  default: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="dashboard-layout">{children}</div>
  ),
}));

vi.mock('@/Components/layout/PageHeader', () => ({
  default: ({ title, subtitle }: { title: string; subtitle?: string }) => (
    <div data-testid="page-header">
      <h1>{title}</h1>
      {subtitle && <p>{subtitle}</p>}
    </div>
  ),
}));

vi.mock('@/Components/theme/use-theme', () => ({
  useTheme: vi.fn(() => ({ theme: 'system', setTheme: vi.fn(), resolvedTheme: 'light' })),
}));

const baseTiers: Record<string, TierConfig> = {
  free: {
    name: 'Free',
    description: 'Get started with basic features.',
    price: 0,
    stripe_price_id: null,
    features: ['1 site', '100 pages', 'Basic analysis'],
  },
  pro: {
    name: 'Pro',
    description: 'For growing businesses.',
    price: 49,
    price_annual: 470,
    stripe_price_id: 'price_pro_monthly',
    stripe_price_id_annual: 'price_pro_annual',
    features: ['5 sites', '1,000 pages', 'Advanced analysis', 'AI drafts'],
  },
  business: {
    name: 'Business',
    description: 'For teams and agencies.',
    price: 99,
    price_annual: 990,
    stripe_price_id: 'price_business_monthly',
    stripe_price_id_annual: 'price_business_annual',
    features: ['25 sites', '10,000 pages', 'Everything in Pro', 'Priority support'],
  },
  enterprise: {
    name: 'Enterprise',
    description: 'Custom solutions for large organizations.',
    price: null,
    contact_only: true,
    features: ['Unlimited sites', 'Unlimited pages', 'Custom integrations', 'Dedicated support'],
  },
};

interface MockPropsOverrides {
  auth?: { user: { id: number; name: string; email: string; is_admin: boolean } | null };
  tiers?: Record<string, TierConfig>;
  current_plan?: string | null;
  is_subscribed?: boolean;
  trial?: { active: boolean; daysRemaining: number; endsAt: string } | null;
  trialEnabled?: boolean;
  trialDays?: number;
  launch_pricing?: boolean;
}

function createMockProps(overrides: MockPropsOverrides = {}) {
  return {
    auth: overrides.auth ?? { user: null },
    features: {
      billing: true,
      apiTokens: false,
      userSettings: false,
      webhooks: false,
      notifications: false,
      socialAuth: false,
      twoFactor: false,
      emailVerification: true,
      onboarding: false,
      apiDocs: false,
      admin: false,
    },
    tiers: overrides.tiers ?? baseTiers,
    current_plan: overrides.current_plan ?? null,
    is_subscribed: overrides.is_subscribed ?? false,
    trial: overrides.trial ?? null,
    trialEnabled: overrides.trialEnabled ?? false,
    trialDays: overrides.trialDays ?? 14,
    launch_pricing: overrides.launch_pricing ?? false,
  };
}

function mockPage(props: ReturnType<typeof createMockProps>) {
  return { props } as unknown as ReturnType<typeof import('@inertiajs/react').usePage<PageProps>>;
}

describe('Pricing', () => {
  describe('testimonials', () => {
    it('does not render hardcoded Sarah K. quote', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      render(<Pricing />);

      expect(screen.queryByText(/Sarah K\./i)).not.toBeInTheDocument();
    });

    it('does not render hardcoded Marcus T. quote', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      render(<Pricing />);

      expect(screen.queryByText(/Marcus T\./i)).not.toBeInTheDocument();
    });
  });

  describe('page title', () => {
    it('renders page title', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      render(<Pricing />);

      expect(document.querySelector('title')).toHaveTextContent('Pricing');
    });
  });

  describe('plan rendering', () => {
    it('renders all plan names', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      render(<Pricing />);

      expect(screen.getAllByText('Free').length).toBeGreaterThanOrEqual(1);
      expect(screen.getByText('Pro')).toBeInTheDocument();
      expect(screen.getByText('Business')).toBeInTheDocument();
      expect(screen.getByText('Enterprise')).toBeInTheDocument();
    });

    it('renders plan descriptions', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      render(<Pricing />);

      expect(screen.getByText('Get started with basic features.')).toBeInTheDocument();
      expect(screen.getByText('For growing businesses.')).toBeInTheDocument();
    });

    it('renders plan features', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      render(<Pricing />);

      expect(screen.getByText('1 site')).toBeInTheDocument();
      expect(screen.getByText('AI drafts')).toBeInTheDocument();
      expect(screen.getByText('Priority support')).toBeInTheDocument();
      expect(screen.getByText('Dedicated support')).toBeInTheDocument();
    });

    it('renders monthly prices by default', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      render(<Pricing />);

      expect(screen.getAllByText('Free').length).toBeGreaterThanOrEqual(1);
      expect(screen.getByText('$49/mo')).toBeInTheDocument();
      expect(screen.getByText('$99/mo')).toBeInTheDocument();
      expect(screen.getByText('Custom')).toBeInTheDocument();
    });
  });

  describe('billing period toggle', () => {
    it('renders annual toggle when annual pricing exists', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      render(<Pricing />);

      expect(screen.getByText('Monthly')).toBeInTheDocument();
      expect(screen.getByText('Annual')).toBeInTheDocument();
    });

    it('does not render toggle when no annual pricing exists', async () => {
      const { usePage } = await import('@inertiajs/react');
      const tiersNoAnnual: Record<string, TierConfig> = {
        free: { ...baseTiers.free },
        pro: { ...baseTiers.pro, price_annual: null },
      };
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ tiers: tiersNoAnnual })));

      render(<Pricing />);

      expect(screen.queryByText('Monthly')).not.toBeInTheDocument();
      expect(screen.queryByText('Annual')).not.toBeInTheDocument();
    });
  });

  describe('CTA buttons (auth-only page)', () => {
    const authUser = {
      user: { id: 1, name: 'Test User', email: 'test@example.com', is_admin: false },
    };

    it('renders upgrade CTA buttons for authenticated user on free plan', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(createMockProps({ auth: authUser, current_plan: 'free' })),
      );

      render(<Pricing />);

      // Auth-only page shows upgrade buttons, not register links
      expect(screen.getByText(/Upgrade to Pro/)).toBeInTheDocument();
      expect(screen.queryByRole('link', { name: /Start Free Analysis/i })).not.toBeInTheDocument();
    });

    it('renders upgrade CTA for pro plan when trial is enabled', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(createMockProps({ auth: authUser, trialEnabled: true, trialDays: 14 })),
      );

      render(<Pricing />);

      expect(screen.getByText(/Upgrade to Pro/)).toBeInTheDocument();
    });

    it('does not render guest trial promotion alert (page is auth-only)', async () => {
      const authUser = {
        user: { id: 1, name: 'Test User', email: 'test@example.com', is_admin: false },
      };
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(createMockProps({ auth: authUser, trialEnabled: true, trialDays: 14 })),
      );

      render(<Pricing />);

      // Guest-only trial alert is not shown on the auth-only billing plans page
      expect(screen.queryByText(/Start with a 14-day free Pro trial/)).not.toBeInTheDocument();
    });
  });

  describe('authenticated user', () => {
    const authUser = {
      user: { id: 1, name: 'Test User', email: 'test@example.com', is_admin: false },
    };

    it('renders upgrade buttons for authenticated user without subscription', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ auth: authUser })));

      render(<Pricing />);

      expect(screen.getByText(/Upgrade to Pro/)).toBeInTheDocument();
      expect(screen.getByText(/Upgrade to Business/)).toBeInTheDocument();
    });

    it('renders switch buttons for subscribed user on different plan', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(createMockProps({ auth: authUser, current_plan: 'pro', is_subscribed: true })),
      );

      render(<Pricing />);

      expect(screen.getByText(/Switch to Business/)).toBeInTheDocument();
    });

    it('renders Current badge for active plan', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(createMockProps({ auth: authUser, current_plan: 'pro', is_subscribed: true })),
      );

      render(<Pricing />);

      expect(screen.getByText('Current')).toBeInTheDocument();
    });

    it('renders Manage Billing for current plan', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(createMockProps({ auth: authUser, current_plan: 'pro', is_subscribed: true })),
      );

      render(<Pricing />);

      expect(screen.getByRole('link', { name: 'Manage Billing' })).toBeInTheDocument();
    });

    it('renders Go to Dashboard for free plan when subscribed', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(createMockProps({ auth: authUser, current_plan: 'pro', is_subscribed: true })),
      );

      render(<Pricing />);

      expect(screen.getByRole('link', { name: 'Go to Dashboard' })).toBeInTheDocument();
    });

    it('renders Contact Sales for enterprise plan', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ auth: authUser })));

      render(<Pricing />);

      expect(screen.getByRole('button', { name: 'Contact Sales' })).toBeInTheDocument();
    });

    it('wraps content in DashboardLayout for authenticated users', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ auth: authUser })));

      render(<Pricing />);

      expect(screen.getByTestId('dashboard-layout')).toBeInTheDocument();
    });

    it('always wraps in DashboardLayout (page requires auth)', async () => {
      const authUser = {
        user: { id: 1, name: 'Test User', email: 'test@example.com', is_admin: false },
      };
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ auth: authUser })));

      render(<Pricing />);

      expect(screen.getByTestId('dashboard-layout')).toBeInTheDocument();
    });
  });

  describe('trial alert', () => {
    const authUser = {
      user: { id: 1, name: 'Test User', email: 'test@example.com', is_admin: false },
    };

    it('renders active trial alert with days remaining', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(
          createMockProps({
            auth: authUser,
            trial: {
              active: true,
              daysRemaining: 5,
              endsAt: '2026-02-28T00:00:00Z',
            },
          }),
        ),
      );

      render(<Pricing />);

      const alertElement = screen.getByRole('alert');
      expect(alertElement.textContent).toContain('5');
      expect(alertElement.textContent).toContain('days');
    });

    it('uses singular day when 1 day remaining', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(
          createMockProps({
            auth: authUser,
            trial: {
              active: true,
              daysRemaining: 1,
              endsAt: '2026-02-24T00:00:00Z',
            },
          }),
        ),
      );

      render(<Pricing />);

      const alertElement = screen.getByRole('alert');
      expect(alertElement.textContent).toContain('1');
      expect(alertElement.textContent).not.toContain('days');
      expect(alertElement.textContent).toContain('day');
    });

    it('does not render trial alert when no trial', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ auth: authUser })));

      render(<Pricing />);

      expect(
        screen.queryByText(/Pro Trial Active|Trial Ending|Trial Expires/),
      ).not.toBeInTheDocument();
    });
  });

  describe('coming soon plans', () => {
    it('renders Coming Soon badge for coming soon plans', async () => {
      const { usePage } = await import('@inertiajs/react');
      const tiersWithComingSoon: Record<string, TierConfig> = {
        ...baseTiers,
        agency: {
          name: 'Agency',
          description: 'For agencies.',
          price: 199,
          coming_soon: true,
          features: ['50 sites'],
        },
      };
      vi.mocked(usePage).mockReturnValue(
        mockPage(
          createMockProps({
            auth: {
              user: { id: 1, name: 'Test', email: 'test@example.com', is_admin: false },
            },
            tiers: tiersWithComingSoon,
          }),
        ),
      );

      render(<Pricing />);

      const comingSoonElements = screen.getAllByText('Coming Soon');
      expect(comingSoonElements.length).toBeGreaterThanOrEqual(1);
    });
  });

  describe('checkout interaction', () => {
    const authUser = {
      user: { id: 1, name: 'Test User', email: 'test@example.com', is_admin: false },
    };

    it('calls router.post for subscribe after confirming checkout dialog (CRO-013)', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ auth: authUser })));

      const user = userEvent.setup();
      render(<Pricing />);

      // CRO-013: clicking upgrade opens a confirmation dialog; router.post fires on confirm
      const upgradeButton = screen.getByText(/Upgrade to Pro/);
      await user.click(upgradeButton);

      const confirmButton = screen.getByText(/Confirm and proceed to checkout/i);
      await user.click(confirmButton);

      expect(router.post).toHaveBeenCalledWith(
        expect.stringContaining('billing'),
        expect.objectContaining({ price_id: 'price_pro_monthly', quantity: 1 }),
        expect.any(Object),
      );
    });

    it('opens swap confirmation dialog when user is already subscribed', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(
        mockPage(createMockProps({ auth: authUser, current_plan: 'pro', is_subscribed: true })),
      );

      const user = userEvent.setup();
      render(<Pricing />);

      const switchButton = screen.getByText(/Switch to Business/);
      await user.click(switchButton);

      // Clicking "Switch to" opens the swap confirmation dialog — router.post is called
      // from within SwapConfirmationDialog after the user confirms, not on initial click
      expect(router.post).not.toHaveBeenCalledWith(
        expect.stringContaining('billing'),
        expect.objectContaining({ price_id: 'price_business_monthly' }),
        expect.any(Object),
      );
    });
  });

  describe('per-seat pricing', () => {
    it('renders per seat info when plan has per_seat and min_seats', async () => {
      const { usePage } = await import('@inertiajs/react');
      const tiersWithSeats: Record<string, TierConfig> = {
        team: {
          name: 'Team',
          description: 'For teams.',
          price: 15,
          per_seat: true,
          min_seats: 3,
          stripe_price_id: 'price_team',
          features: ['Team features'],
        },
      };
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ tiers: tiersWithSeats })));

      render(<Pricing />);

      expect(screen.getByText(/per seat, min 3 seats/)).toBeInTheDocument();
    });
  });

  describe('launch pricing badge', () => {
    it('renders the launch pricing badge on the Pro card when flag is enabled', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ launch_pricing: true })));

      render(<Pricing />);

      expect(
        screen.getByText(/Launch pricing — locked in for life when you upgrade during beta\./i),
      ).toBeInTheDocument();
    });

    it('does not render the launch pricing badge when flag is disabled', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps({ launch_pricing: false })));

      render(<Pricing />);

      expect(
        screen.queryByText(/Launch pricing — locked in for life when you upgrade during beta\./i),
      ).not.toBeInTheDocument();
    });
  });

  describe('analytics tracking (ANA-007)', () => {
    beforeEach(() => {
      vi.clearAllMocks();
    });

    it('fires PRICING_VIEWED event on mount with billing_page source', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      const { trackProductEvent } = await import('@/lib/analytics');

      render(<Pricing />);

      expect(vi.mocked(trackProductEvent)).toHaveBeenCalledWith(
        'pricing_viewed',
        expect.objectContaining({ source: 'billing_page' }),
      );
    });

    it('includes plan_count in PRICING_VIEWED event', async () => {
      const { usePage } = await import('@inertiajs/react');
      vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

      const { trackProductEvent } = await import('@/lib/analytics');

      render(<Pricing />);

      // baseTiers has 4 plans: free, pro, business, enterprise
      expect(vi.mocked(trackProductEvent)).toHaveBeenCalledWith(
        'pricing_viewed',
        expect.objectContaining({ plan_count: 4 }),
      );
    });
  });
});
