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

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

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

import BillingIndex from './Index';

// Mock Inertia
vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    usePage: vi.fn(() => ({
      props: {
        subscription: null,
        platform_trial: null,
        incomplete_payment: null,
        invoices: [],
        grace_days: 7,
        auth: {
          user: { id: 1, name: 'Test User', email: 'test@example.com', is_admin: false },
        },
        features: {
          billing: true,
          apiTokens: true,
          userSettings: true,
          webhooks: false,
          notifications: false,
          socialAuth: false,
          twoFactor: false,
          emailVerification: true,
          onboarding: false,
          apiDocs: false,
          admin: false,
        },
      },
    })),
    router: {
      visit: vi.fn(),
      reload: vi.fn(),
      on: vi.fn(() => vi.fn()),
    },
    Head: ({ children }: { children?: React.ReactNode }) => <>{children}</>,
    Link: ({ children, href }: { children: React.ReactNode; href: string }) => (
      <a href={href}>{children}</a>
    ),
  };
});

// Mock route helper
vi.mock('ziggy-js', () => ({
  route: (name: string) => `/${name.replace(/\./g, '/')}`,
}));

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

// Helper to create a typed mock page object for usePage
const mockPage = (props: ReturnType<typeof createMockProps>) =>
  ({ props }) as unknown as ReturnType<typeof import('@inertiajs/react').usePage<PageProps>>;

// Shared mock props factory
const createMockProps = (overrides: Record<string, unknown> = {}) => ({
  auth: {
    user: { id: 1, name: 'Test User', email: 'test@example.com', is_admin: false },
  },
  features: {
    billing: true,
    apiTokens: true,
    userSettings: true,
    webhooks: false,
    notifications: false,
    socialAuth: false,
    twoFactor: false,
    emailVerification: true,
    onboarding: false,
    apiDocs: false,
    admin: false,
  },
  subscription: null,
  platform_trial: null,
  incomplete_payment: null,
  invoices: [],
  grace_days: 7,
  ...overrides,
});

describe('Billing Index Page', () => {
  it('renders billing page for user without subscription', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

    render(<BillingIndex />);

    expect(screen.getByRole('heading', { name: 'Billing', level: 1 })).toBeInTheDocument();
    expect(screen.getByText('Manage your subscription and payment details')).toBeInTheDocument();
    expect(screen.getByText('Ready to unlock premium features?')).toBeInTheDocument();
    expect(screen.getByText('View Plans')).toBeInTheDocument();
  });

  it('renders platform trial status', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          platform_trial: {
            endsAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
            daysRemaining: 7,
          },
        }),
      ),
    );

    render(<BillingIndex />);

    expect(screen.getByText(/Trial Ending Soon|Pro Trial Active/)).toBeInTheDocument();
    expect(screen.getByText(/7.*Days|7 days/)).toBeInTheDocument();
    expect(screen.getByText('Upgrade now')).toBeInTheDocument();
  });

  it('renders active subscription status', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'active',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt: null,
            onGracePeriod: false,
            canceled: false,
            active: true,
          },
        }),
      ),
    );

    render(<BillingIndex />);

    expect(screen.getByText('Pro')).toBeInTheDocument();
    expect(screen.getByText('Manage Billing')).toBeInTheDocument();
    expect(screen.getByText('Cancel Subscription')).toBeInTheDocument();
  });

  it('renders canceled subscription on grace period', async () => {
    const { usePage } = await import('@inertiajs/react');
    const endsAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();

    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'active',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt,
            onGracePeriod: true,
            canceled: true,
            active: false,
          },
        }),
      ),
    );

    render(<BillingIndex />);

    expect(screen.getByText('Subscription Ending')).toBeInTheDocument();
    expect(screen.getByText('Resume Subscription')).toBeInTheDocument();
  });

  it('renders incomplete payment alert', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'incomplete',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt: null,
            onGracePeriod: false,
            canceled: false,
            active: false,
          },
          incomplete_payment: {
            paymentId: 'pi_test123',
            confirmUrl: '/billing?confirm=true',
          },
        }),
      ),
    );

    render(<BillingIndex />);

    expect(screen.getByText('Payment Confirmation Required')).toBeInTheDocument();
    expect(screen.getByText('Complete payment now')).toBeInTheDocument();
  });

  it('renders past due subscription alert', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'past_due',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt: null,
            onGracePeriod: false,
            canceled: false,
            active: true,
          },
        }),
      ),
    );

    render(<BillingIndex />);

    expect(screen.getByText('Payment Failed — Action Required')).toBeInTheDocument();
    expect(screen.getByText(/access to AI drafts/)).toBeInTheDocument();
  });

  it('renders invoice list for subscribed user', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'active',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt: null,
            onGracePeriod: false,
            canceled: false,
            active: true,
          },
          invoices: [
            {
              id: 'in_test123',
              date: new Date('2025-01-15').toISOString(),
              amount: 49,
              status: 'paid',
              invoice_pdf: 'https://invoice.stripe.com/i/test123',
            },
            {
              id: 'in_test456',
              date: new Date('2024-12-15').toISOString(),
              amount: 49,
              status: 'paid',
              invoice_pdf: 'https://invoice.stripe.com/i/test456',
            },
          ],
        }),
      ),
    );

    render(<BillingIndex />);

    expect(screen.getByText('Billing History')).toBeInTheDocument();
    expect(screen.getAllByText('$49.00')).toHaveLength(2);
    expect(screen.getAllByText('Paid')).toHaveLength(2);
  });

  it('shows empty state for invoices when none exist', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'active',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt: null,
            onGracePeriod: false,
            canceled: false,
            active: true,
          },
        }),
      ),
    );

    render(<BillingIndex />);

    expect(screen.getByText('No invoices yet')).toBeInTheDocument();
    expect(
      screen.getByText('Your invoices will appear here after your first billing cycle.'),
    ).toBeInTheDocument();
  });

  it('opens billing portal when manage billing clicked', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'active',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt: null,
            onGracePeriod: false,
            canceled: false,
            active: true,
          },
        }),
      ),
    );

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

    const manageButton = screen.getByText('Manage Billing');
    await user.click(manageButton);

    expect(router.visit).toHaveBeenCalledWith('/billing/portal', expect.any(Object));
  });

  it('opens cancel subscription modal when cancel button clicked', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'active',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt: null,
            onGracePeriod: false,
            canceled: false,
            active: true,
          },
        }),
      ),
    );

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

    const cancelButton = screen.getByText('Cancel Subscription');
    await user.click(cancelButton);

    // Modal should open (component is imported and used)
    // Since we're not testing the modal itself here, just verify button interaction works
    expect(cancelButton).toBeInTheDocument();
  });

  it('displays checkout success alert when query param present', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

    // Mock window.location.search
    delete (window as unknown as { location?: unknown }).location;
    (window as unknown as { location: { search: string; pathname: string } }).location = {
      search: '?checkout=success',
      pathname: '/billing',
    };
    const replaceStateSpy = vi.spyOn(window.history, 'replaceState');

    render(<BillingIndex />);

    await waitFor(() => {
      expect(screen.getByText(/Welcome to/)).toBeInTheDocument();
    });

    expect(replaceStateSpy).toHaveBeenCalledWith({}, '', '/billing');
  });

  it('shows view all invoices button when more than 5 invoices', async () => {
    const { usePage } = await import('@inertiajs/react');
    const invoices = Array.from({ length: 10 }, (_, i) => ({
      id: `in_test${i}`,
      date: new Date(2025, 0, i + 1).toISOString(),
      amount: 49,
      status: 'paid',
      invoice_pdf: `https://invoice.stripe.com/i/test${i}`,
    }));

    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          subscription: {
            name: 'Pro',
            status: 'active',
            priceId: 'price_pro_monthly',
            trialEndsAt: null,
            endsAt: null,
            onGracePeriod: false,
            canceled: false,
            active: true,
          },
          invoices,
        }),
      ),
    );

    render(<BillingIndex />);

    expect(screen.getByText('View all 10 invoices')).toBeInTheDocument();
  });

  it('does not show billing history card when no subscription', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(mockPage(createMockProps()));

    render(<BillingIndex />);

    expect(screen.queryByText('Billing History')).not.toBeInTheDocument();
  });

  it('shows trial-aware CTA on checkout success when trial is active and all setup done', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          platform_trial: {
            endsAt: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000).toISOString(),
            daysRemaining: 5,
          },
          setup_state: {
            has_sites: true,
            has_gsc: true,
            has_analysis: true,
            has_ai_key: true,
          },
          sites: [{ id: 42, name: 'My Site', domain: 'example.com' }],
        }),
      ),
    );

    delete (window as unknown as { location?: unknown }).location;
    (window as unknown as { location: { search: string; pathname: string } }).location = {
      search: '?checkout=success',
      pathname: '/billing',
    };

    render(<BillingIndex />);

    await waitFor(() => {
      expect(screen.getByText(/Start your first analysis/)).toBeInTheDocument();
    });

    expect(screen.getByText(/5 days left in trial/)).toBeInTheDocument();
  });

  it('shows generic CTA on checkout success when no trial is active and all setup done', async () => {
    const { usePage } = await import('@inertiajs/react');
    vi.mocked(usePage).mockReturnValue(
      mockPage(
        createMockProps({
          platform_trial: null,
          setup_state: {
            has_sites: true,
            has_gsc: true,
            has_analysis: true,
            has_ai_key: true,
          },
          sites: [{ id: 42, name: 'My Site', domain: 'example.com' }],
        }),
      ),
    );

    delete (window as unknown as { location?: unknown }).location;
    (window as unknown as { location: { search: string; pathname: string } }).location = {
      search: '?checkout=success',
      pathname: '/billing',
    };

    render(<BillingIndex />);

    await waitFor(() => {
      expect(screen.getByText('See Your SEO Opportunities')).toBeInTheDocument();
    });
  });
});
