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

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

vi.mock('recharts', () => ({
  BarChart: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="bar-chart">{children}</div>
  ),
  Bar: () => <div />,
  XAxis: () => <div />,
  YAxis: () => <div />,
  CartesianGrid: () => <div />,
  Tooltip: () => <div />,
  ResponsiveContainer: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  PieChart: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="pie-chart">{children}</div>
  ),
  Pie: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  Cell: () => <div />,
  LineChart: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="line-chart">{children}</div>
  ),
  Line: () => <div />,
}));

vi.mock('@/Components/ui/chart', async () => {
  const recharts = await import('recharts');
  return {
    BarChart: recharts.BarChart,
    Bar: recharts.Bar,
    XAxis: recharts.XAxis,
    YAxis: recharts.YAxis,
    CartesianGrid: recharts.CartesianGrid,
    ChartTooltip: recharts.Tooltip,
    ChartContainer: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
    PieChart: recharts.PieChart,
    Pie: recharts.Pie,
    Cell: recharts.Cell,
    LineChart: recharts.LineChart,
    Line: recharts.Line,
  };
});

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/metrics',
      props: {
        auth: { user: { name: 'Admin', email: 'admin@test.com' } },
        features: {
          billing: false,
          socialAuth: false,
          emailVerification: false,
          apiTokens: true,
          notifications: false,
          admin: true,
          twoFactor: false,
          webhooks: false,
          branding: false,
          customDomain: false,
        },
      },
    })),
    Link: ({
      children,
      href,
      ...rest
    }: {
      children: React.ReactNode;
      href: string;
      className?: string;
    }) => (
      <a href={href} {...rest}>
        {children}
      </a>
    ),
  };
});

// ─── Fixtures ─────────────────────────────────────────────────────────────────

const mockFunnel = {
  stages: [
    { name: 'Signup', users: 100, rate: 100.0 },
    { name: 'Site Added', users: 80, rate: 80.0 },
    { name: 'GSC Connected', users: 60, rate: 60.0 },
    { name: 'WP Connected', users: 40, rate: 40.0 },
    { name: 'Analysis Run', users: 30, rate: 30.0 },
    { name: 'Rec Reviewed', users: 20, rate: 20.0 },
    { name: 'Draft Generated', users: 15, rate: 15.0 },
    { name: 'Published', users: 10, rate: 10.0 },
    { name: 'Subscription Started', users: 5, rate: 5.0 },
    { name: 'Retained (30d)', users: 25, rate: 25.0 },
  ],
  activation_rate: 30.0,
};

const mockCohorts = [
  {
    cohort_label: '2026-W08',
    size: 20,
    day_1: { activated: 4, rate: 0.2 },
    day_3: { activated: 6, rate: 0.3 },
    day_7: { activated: 8, rate: 0.4 },
    day_14: { activated: 10, rate: 0.5 },
    day_30: { activated: 12, rate: 0.6 },
  },
  {
    cohort_label: '2026-W09',
    size: 15,
    day_1: { activated: 3, rate: 0.2 },
    day_3: { activated: 5, rate: 0.33 },
    day_7: { activated: 7, rate: 0.47 },
    day_14: { activated: 8, rate: 0.53 },
    day_30: { activated: 9, rate: 0.6 },
  },
];

const mockFeatureAdoption = [
  { feature: 'gsc_connection', adopted_count: 80, active_users: 100, rate: 0.8 },
  { feature: 'ai_draft', adopted_count: 50, active_users: 100, rate: 0.5 },
  { feature: 'seo_calendar', adopted_count: 20, active_users: 100, rate: 0.2 },
  { feature: 'site_connected', adopted_count: 90, active_users: 100, rate: 0.9 },
  { feature: 'analysis', adopted_count: 70, active_users: 100, rate: 0.7 },
  { feature: 'serp_analysis', adopted_count: 30, active_users: 100, rate: 0.3 },
  { feature: 'content_briefs', adopted_count: 25, active_users: 100, rate: 0.25 },
  { feature: 'content_intelligence_topics', adopted_count: 15, active_users: 100, rate: 0.15 },
  {
    feature: 'content_intelligence_cannibalization',
    adopted_count: 10,
    active_users: 100,
    rate: 0.1,
  },
  { feature: 'wp_publish', adopted_count: 40, active_users: 100, rate: 0.4 },
];

const mockChurnSummary = {
  healthy: 60,
  monitor: 20,
  at_risk: 15,
  critical: 5,
  weekly_trend: -0.05,
  top_at_risk: [{ user_id: 1, email: 'user@example.com', days_inactive: 45 }],
};

const mockActivationRateTrend = [
  { week: 'Feb 03', signups: 12, activated: 3, rate: 25.0 },
  { week: 'Feb 10', signups: 15, activated: 5, rate: 33.3 },
  { week: 'Feb 17', signups: 10, activated: 4, rate: 40.0 },
  { week: 'Feb 24', signups: 18, activated: 7, rate: 38.9 },
];

const mockTtvStats = {
  median_minutes: 45.0,
  p90_minutes: 120.0,
  sample_size: 42,
};

const mockTtaStats = {
  median_minutes: 8.0,
  p90_minutes: 22.0,
  sample_size: 38,
  target_minutes: 10,
};

const defaultProps = {
  funnel: mockFunnel,
  cohorts: mockCohorts,
  feature_adoption: mockFeatureAdoption,
  churn_summary: mockChurnSummary,
  total_users: 100,
  active_users_30d: 60,
  new_users_7d: 10,
  activation_rate: 30.0,
  activation_rate_trend: mockActivationRateTrend,
  ttv_stats: mockTtvStats,
  time_to_activation_stats: mockTtaStats,
  churn_threshold: 20,
  last_refreshed_at: new Date().toISOString(),
};

// ─── Tests ───────────────────────────────────────────────────────────────────

import MetricsDashboard from './MetricsDashboard';

describe('Admin/MetricsDashboard', () => {
  it('renders KPI cards', () => {
    render(<MetricsDashboard {...defaultProps} />);

    expect(screen.getByText('Total Users')).toBeInTheDocument();
    expect(screen.getByText('Active (engaged) last 30d')).toBeInTheDocument();
    expect(screen.getByText('New (7d)')).toBeInTheDocument();
    expect(screen.getByText('Activation Rate')).toBeInTheDocument();
  });

  it('renders funnel chart with all stages', async () => {
    render(<MetricsDashboard {...defaultProps} />);

    expect(screen.getByText('Activation Funnel')).toBeInTheDocument();
    // Bar charts are lazy-loaded — wait for Suspense to resolve
    await waitFor(() =>
      expect(screen.getAllByTestId('bar-chart').length).toBeGreaterThanOrEqual(1),
    );
  });

  it('renders cohort table with day columns', () => {
    render(<MetricsDashboard {...defaultProps} />);

    expect(screen.getByText('Cohort Activation (Last 12 Weeks)')).toBeInTheDocument();
    expect(screen.getByText('Day 1')).toBeInTheDocument();
    expect(screen.getByText('Day 7')).toBeInTheDocument();
    expect(screen.getByText('Day 30')).toBeInTheDocument();
    expect(screen.getByText('2026-W08')).toBeInTheDocument();
    expect(screen.getByText('2026-W09')).toBeInTheDocument();
  });

  it('renders feature adoption chart', async () => {
    render(<MetricsDashboard {...defaultProps} />);

    expect(screen.getByText('Feature Adoption')).toBeInTheDocument();
    // Bar charts are lazy-loaded — wait for Suspense to resolve
    await waitFor(() =>
      expect(screen.getAllByTestId('bar-chart').length).toBeGreaterThanOrEqual(2),
    );
  });

  it('renders churn distribution', () => {
    render(<MetricsDashboard {...defaultProps} />);

    expect(screen.getByText('Churn Risk Distribution')).toBeInTheDocument();
    expect(screen.getByText('Healthy')).toBeInTheDocument();
    expect(screen.getByText('At Risk')).toBeInTheDocument();
    expect(screen.getByText('Critical')).toBeInTheDocument();
  });

  it('renders empty state when cohorts list is empty', () => {
    render(<MetricsDashboard {...defaultProps} cohorts={[]} />);
    expect(screen.getByText('No cohort data available.')).toBeInTheDocument();
  });

  it('renders empty state when funnel is empty', () => {
    render(<MetricsDashboard {...defaultProps} funnel={{ stages: [], activation_rate: 0 }} />);
    expect(screen.getByText('No funnel data available.')).toBeInTheDocument();
  });

  it('renders activation rate trend section heading', () => {
    render(<MetricsDashboard {...defaultProps} />);
    expect(screen.getByText('Activation Rate Trend (8 weeks)')).toBeInTheDocument();
  });

  it('renders activation rate trend empty state when trend data is empty', () => {
    render(<MetricsDashboard {...defaultProps} activation_rate_trend={[]} />);
    expect(screen.getByText('No activation trend data available.')).toBeInTheDocument();
  });

  it('renders TTV stats section heading', () => {
    render(<MetricsDashboard {...defaultProps} />);
    expect(screen.getByText('Time to Value (TTV)')).toBeInTheDocument();
  });

  it('renders median and p90 TTV values when sample_size > 0', () => {
    render(<MetricsDashboard {...defaultProps} />);
    expect(screen.getByText('Median TTV')).toBeInTheDocument();
    expect(screen.getByText('p90 TTV')).toBeInTheDocument();
    // 45 minutes → "45m"; 120 minutes = 2.0 hours → "2.0h"
    expect(screen.getByText('45m')).toBeInTheDocument();
    expect(screen.getByText('2.0h')).toBeInTheDocument();
  });

  it('renders TTV empty state when sample_size is 0', () => {
    render(
      <MetricsDashboard
        {...defaultProps}
        ttv_stats={{ median_minutes: null, p90_minutes: null, sample_size: 0 }}
      />,
    );
    expect(screen.getByText('No TTV data yet — activate more users.')).toBeInTheDocument();
  });

  it('renders KPI card numeric values', () => {
    render(<MetricsDashboard {...defaultProps} />);
    // total_users=100, active_users_30d=60, new_users_7d=10
    // Use getAllByText since 60 may appear in both the KPI card and churn distribution
    expect(screen.getAllByText('100').length).toBeGreaterThanOrEqual(1);
    expect(screen.getAllByText('60').length).toBeGreaterThanOrEqual(1);
    expect(screen.getAllByText('10').length).toBeGreaterThanOrEqual(1);
  });

  it('labels the active KPI as engagement-based', () => {
    render(<MetricsDashboard {...defaultProps} />);
    expect(screen.getByText('Active (engaged) last 30d')).toBeInTheDocument();
  });

  it('renders activation rate value with percent sign', () => {
    render(<MetricsDashboard {...defaultProps} />);
    // activation_rate=30.0 → format: (n) => `${n}%` → "30%"
    // Multiple "30%" occurrences may appear (cohort cells etc.) — verify at least one exists
    expect(screen.getAllByText('30%').length).toBeGreaterThanOrEqual(1);
  });

  it('renders churn Monitor count', () => {
    render(<MetricsDashboard {...defaultProps} />);
    expect(screen.getByText('Monitor')).toBeInTheDocument();
  });

  it('renders churn summary counts for at_risk and critical tiers', () => {
    render(<MetricsDashboard {...defaultProps} />);
    // at_risk=15, critical=5 — unique numbers in the churn distribution
    expect(screen.getAllByText('15').length).toBeGreaterThanOrEqual(1);
    expect(screen.getAllByText('5').length).toBeGreaterThanOrEqual(1);
  });

  it('renders sample_size in TTV section', () => {
    render(<MetricsDashboard {...defaultProps} />);
    // sample_size=42 shown somewhere in TTV section
    expect(screen.getByText(/42/)).toBeInTheDocument();
  });

  it('renders TTA section heading', () => {
    render(<MetricsDashboard {...defaultProps} />);
    expect(screen.getByText('Time to Activation (TTA)')).toBeInTheDocument();
  });

  it('renders TTA target in card description', () => {
    render(<MetricsDashboard {...defaultProps} />);
    // target_minutes=10 → "target: <10m"
    expect(screen.getByText(/target:.*10m/)).toBeInTheDocument();
  });

  it('renders median and p90 TTA values when sample_size > 0', () => {
    render(<MetricsDashboard {...defaultProps} />);
    expect(screen.getByText('Median TTA')).toBeInTheDocument();
    expect(screen.getByText('p90 TTA')).toBeInTheDocument();
    // median=8.0 → "8m"; p90=22.0 → "22m"
    expect(screen.getByText('8m')).toBeInTheDocument();
    expect(screen.getByText('22m')).toBeInTheDocument();
  });

  it('renders TTA empty state when sample_size is 0', () => {
    render(
      <MetricsDashboard
        {...defaultProps}
        time_to_activation_stats={{
          median_minutes: null,
          p90_minutes: null,
          sample_size: 0,
          target_minutes: 10,
        }}
      />,
    );
    expect(screen.getByText('No TTA data yet — activate more users.')).toBeInTheDocument();
  });

  it('renders TTA sample_size', () => {
    render(<MetricsDashboard {...defaultProps} />);
    // sample_size=38
    expect(screen.getByText(/38/)).toBeInTheDocument();
  });

  it('applies success color when median TTA is within target', () => {
    render(<MetricsDashboard {...defaultProps} />);
    // median=8m, target=10m → median <= target → text-success class
    const medianEl = screen.getByText('8m');
    expect(medianEl.className).toContain('text-success');
  });

  it('applies destructive color when median TTA exceeds target', () => {
    render(
      <MetricsDashboard
        {...defaultProps}
        time_to_activation_stats={{
          median_minutes: 15.0,
          p90_minutes: 35.0,
          sample_size: 20,
          target_minutes: 10,
        }}
      />,
    );
    // median=15m, target=10m → median > target → text-destructive class
    const medianEl = screen.getByText('15m');
    expect(medianEl.className).toContain('text-destructive');
  });
});
