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

import type { AdminDashboardProps } from '@/types/admin';

vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    Head: ({ title }: { title: string }) => <title>{title}</title>,
    usePage: vi.fn(() => ({
      url: '/admin',
      props: {
        auth: { user: { name: 'Admin', email: 'admin@test.com' } },
        features: {
          billing: false,
          socialAuth: false,
          emailVerification: true,
          apiTokens: true,
          userSettings: true,
          notifications: false,
        },
      },
    })),
    Link: ({
      children,
      href,
      ...rest
    }: {
      children: React.ReactNode;
      href: string;
      className?: string;
    }) => (
      <a href={href} {...rest}>
        {children}
      </a>
    ),
  };
});

vi.mock('@/Components/ui/count-up', () => ({
  CountUp: ({ end, format }: { end: number; format?: (n: number) => string }) => (
    <span>{format ? format(end) : end}</span>
  ),
}));

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

// Recharts mocks — prevent canvas-related errors in jsdom
vi.mock('recharts', () => ({
  ResponsiveContainer: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  AreaChart: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="area-chart">{children}</div>
  ),
  BarChart: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="bar-chart">{children}</div>
  ),
  Area: () => null,
  Bar: () => null,
  LabelList: () => null,
  XAxis: () => null,
  YAxis: () => null,
  CartesianGrid: () => null,
  Tooltip: () => null,
  Legend: () => null,
  defs: () => null,
  linearGradient: () => null,
  stop: () => null,
}));

import AdminDashboard from './Dashboard';

const defaultProps: AdminDashboardProps = {
  stats: {
    total_users: 150,
    new_users_7d: 12,
    new_users_30d: 45,
    admin_count: 3,
  },
  signup_chart: [
    { date: '2025-01-01', count: 5 },
    { date: '2025-01-02', count: 8 },
  ],
  activation_funnel: {
    stages: [
      { name: 'Signed Up', users: 100, rate: 100 },
      { name: 'Created a Site', users: 60, rate: 60 },
      { name: 'Connected GSC', users: 40, rate: 40 },
      { name: 'Connected WordPress', users: 35, rate: 35 },
      { name: 'Ran First Analysis', users: 25, rate: 25 },
      { name: 'First Recommendation', users: 20, rate: 20 },
      { name: 'Applied Recommendation', users: 10, rate: 10 },
    ],
    activation_rate: 10,
  },
  recent_activity: [
    {
      id: 1,
      event: 'auth.login',
      user_id: 1,
      user_name: 'John Doe',
      user_email: 'john@test.com',
      ip: '192.168.1.1',
      created_at: new Date().toISOString(),
    },
  ],
  operational_health: {
    queue_size: 0,
    failed_jobs_1h: 0,
    circuit_breakers: {},
    last_gsc_sync: null,
  },
  cancellation_reasons: [],
  last_refreshed_at: new Date().toISOString(),
};

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

  it('renders stats grid with user counts', () => {
    render(<AdminDashboard {...defaultProps} />);
    expect(screen.getByText('Total Users')).toBeInTheDocument();
    expect(screen.getByText('150')).toBeInTheDocument();
    expect(screen.getByText('New (7d)')).toBeInTheDocument();
    expect(screen.getByText('12')).toBeInTheDocument();
  });

  it('renders admin count stat', () => {
    render(<AdminDashboard {...defaultProps} />);
    expect(screen.getByText('Admins')).toBeInTheDocument();
    expect(screen.getByText('3')).toBeInTheDocument();
  });

  it('renders signup chart section', () => {
    render(<AdminDashboard {...defaultProps} />);
    expect(screen.getByText('User Signups')).toBeInTheDocument();
  });

  it('renders recent activity table', () => {
    render(<AdminDashboard {...defaultProps} />);
    expect(screen.getByText('Recent Activity')).toBeInTheDocument();
    expect(screen.getByText('auth.login')).toBeInTheDocument();
    expect(screen.getByText('John Doe')).toBeInTheDocument();
  });

  it('renders recent activity IP', () => {
    render(<AdminDashboard {...defaultProps} />);
    expect(screen.getByText('192.168.1.1')).toBeInTheDocument();
  });

  it('shows empty state for activity when none exist', () => {
    render(<AdminDashboard {...defaultProps} recent_activity={[]} />);
    expect(screen.getByText('No activity recorded yet')).toBeInTheDocument();
  });

  it('shows active subscriptions stat when billing enabled', () => {
    render(
      <AdminDashboard
        {...defaultProps}
        stats={{ ...defaultProps.stats, active_subscriptions: 25 }}
      />,
    );
    expect(screen.getByText('Active Subscriptions')).toBeInTheDocument();
    expect(screen.getByText('25')).toBeInTheDocument();
  });

  it('does not show subscriptions stat when not in stats', () => {
    render(<AdminDashboard {...defaultProps} />);
    expect(screen.queryByText('Active Subscriptions')).not.toBeInTheDocument();
  });

  it('renders system user as fallback for activity without user', () => {
    const activity = [
      {
        id: 2,
        event: 'system.check',
        user_id: null,
        user_name: null,
        user_email: null,
        ip: '127.0.0.1',
        created_at: new Date().toISOString(),
      },
    ];
    render(<AdminDashboard {...defaultProps} recent_activity={activity} />);
    // "System" appears in both sidebar nav and activity table — verify it appears more than once
    const systemElements = screen.getAllByText('System');
    expect(systemElements.length).toBeGreaterThanOrEqual(2);
  });

  it('links stat cards to filtered admin pages', () => {
    render(<AdminDashboard {...defaultProps} />);
    const links = screen.getAllByRole('link');
    const hrefs = links.map((l) => l.getAttribute('href'));
    expect(hrefs).toContain('/admin/users');
    expect(hrefs).toContain('/admin/users?admin=1');
  });

  it('renders activation funnel section', () => {
    render(<AdminDashboard {...defaultProps} />);
    expect(screen.getByText('Activation Funnel')).toBeInTheDocument();
    expect(
      screen.getByText('User progression through key milestones (last 30 days)'),
    ).toBeInTheDocument();
  });

  it('renders funnel empty state when no data', async () => {
    render(<AdminDashboard {...defaultProps} activation_funnel={{ stages: [], activation_rate: 0 }} />);
    await waitFor(() => {
      expect(screen.getByText('No funnel data yet')).toBeInTheDocument();
    });
  });

  it('shows activation rate percentage in funnel heading when non-zero', () => {
    render(<AdminDashboard {...defaultProps} activation_funnel={{ ...defaultProps.activation_funnel, activation_rate: 10 }} />);
    expect(screen.getByText('10% activation rate')).toBeInTheDocument();
  });

  it('renders operational health section with queue size and failed jobs', () => {
    render(
      <AdminDashboard
        {...defaultProps}
        operational_health={{ queue_size: 42, failed_jobs_1h: 5, circuit_breakers: {}, last_gsc_sync: null }}
      />,
    );
    expect(screen.getByText('Operational Health')).toBeInTheDocument();
    expect(screen.getByText('Queue Size')).toBeInTheDocument();
    expect(screen.getByText('42')).toBeInTheDocument();
    expect(screen.getByText('Failed Jobs (1h)')).toBeInTheDocument();
    expect(screen.getByText('5')).toBeInTheDocument();
  });

  it('renders circuit breaker badges when circuit_breakers data present', () => {
    render(
      <AdminDashboard
        {...defaultProps}
        operational_health={{
          queue_size: 0,
          failed_jobs_1h: 0,
          circuit_breakers: { openai: 'closed', gsc: 'open' },
          last_gsc_sync: null,
        }}
      />,
    );
    expect(screen.getByText('openai: closed')).toBeInTheDocument();
    expect(screen.getByText('gsc: open')).toBeInTheDocument();
  });

  it('shows Never for last GSC sync when null', () => {
    render(
      <AdminDashboard
        {...defaultProps}
        operational_health={{ queue_size: 0, failed_jobs_1h: 0, circuit_breakers: {}, last_gsc_sync: null }}
      />,
    );
    expect(screen.getByText('Never')).toBeInTheDocument();
  });

  it('renders cancellation reasons section when data present', () => {
    render(
      <AdminDashboard
        {...defaultProps}
        cancellation_reasons={[
          { reason: 'too_expensive', count: 5 },
          { reason: 'missing_features', count: 3 },
          { reason: null, count: 1 },
        ]}
      />,
    );
    expect(screen.getByText('Cancellation Reasons')).toBeInTheDocument();
    expect(screen.getByText('Too Expensive')).toBeInTheDocument();
    expect(screen.getByText('Missing Features')).toBeInTheDocument();
    // null reason falls back to 'Not specified'
    expect(screen.getByText('Not specified')).toBeInTheDocument();
  });

  it('does not render cancellation reasons section when empty', () => {
    render(<AdminDashboard {...defaultProps} cancellation_reasons={[]} />);
    expect(screen.queryByText('Cancellation Reasons')).not.toBeInTheDocument();
  });

  it('renders plan tier breakdown section when billing stats present', () => {
    render(
      <AdminDashboard
        {...defaultProps}
        stats={{
          ...defaultProps.stats,
          free_users: 80,
          trial_users: 15,
          paid_users: 55,
        }}
      />,
    );
    expect(screen.getByText('Free Users')).toBeInTheDocument();
    expect(screen.getByText('80')).toBeInTheDocument();
    expect(screen.getByText('Trial Users')).toBeInTheDocument();
    expect(screen.getByText('15')).toBeInTheDocument();
    expect(screen.getByText('Paid Users')).toBeInTheDocument();
    expect(screen.getByText('55')).toBeInTheDocument();
  });

  it('renders trial conversion rate stat when present', () => {
    render(
      <AdminDashboard
        {...defaultProps}
        stats={{ ...defaultProps.stats, trial_conversion_rate: 34 }}
      />,
    );
    expect(screen.getByText('Trial Conversion')).toBeInTheDocument();
    expect(screen.getByText('34%')).toBeInTheDocument();
  });

  it('renders New (30d) stat card', () => {
    render(<AdminDashboard {...defaultProps} />);
    expect(screen.getByText('New (30d)')).toBeInTheDocument();
    expect(screen.getByText('45')).toBeInTheDocument();
  });

  it('links recent activity events to audit log detail pages', () => {
    render(<AdminDashboard {...defaultProps} />);
    const links = screen.getAllByRole('link');
    const hrefs = links.map((l) => l.getAttribute('href'));
    expect(hrefs).toContain('/admin/audit-logs/1');
  });
});
