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

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/breach-incidents',
      props: {
        auth: { user: { id: 1, name: 'Admin', email: 'admin@test.com', is_admin: true } },
        features: {
          billing: false,
          socialAuth: false,
          emailVerification: true,
          apiTokens: true,
          userSettings: true,
          notifications: false,
          onboarding: false,
          apiDocs: false,
          twoFactor: false,
          webhooks: false,
          admin: true,
        },
      },
    })),
    Link: ({
      children,
      href,
      ...rest
    }: {
      children: React.ReactNode;
      href: string;
      className?: string;
    }) => (
      <a href={href} {...rest}>
        {children}
      </a>
    ),
    router: {
      patch: vi.fn(),
      delete: vi.fn(),
      post: vi.fn(),
      get: vi.fn(),
      visit: vi.fn(),
      on: vi.fn(() => vi.fn()),
    },
  };
});

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

vi.mock('sonner', () => ({
  toast: { success: vi.fn(), error: vi.fn() },
}));

import BreachIncidentsIndex from './Index';

const makePagination = <T,>(data: T[]) => ({
  data,
  current_page: 1,
  last_page: 1,
  from: data.length > 0 ? 1 : null,
  to: data.length > 0 ? data.length : null,
  total: data.length,
});

const makeIncident = (overrides = {}) => ({
  id: 1,
  description: 'Unauthorized access to user database',
  severity: 'high',
  affected_count: 250,
  status: 'investigating',
  is_notified: false,
  is_overdue: false,
  detected_at: '2026-03-20T08:00:00Z',
  notification_deadline: '2026-03-23T08:00:00Z',
  notified_at: null,
  ...overrides,
});

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

  it('renders the page heading', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([makeIncident()])} filters={{}} />,
    );
    expect(screen.getByText('Data Breach Incidents')).toBeInTheDocument();
  });

  it('renders incident description', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([makeIncident()])} filters={{}} />,
    );
    expect(screen.getByText('Unauthorized access to user database')).toBeInTheDocument();
  });

  it('shows severity badge', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([makeIncident({ severity: 'critical' })])}
        filters={{}}
      />,
    );
    expect(screen.getByText('critical')).toBeInTheDocument();
  });

  it('shows status badge', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([makeIncident({ status: 'contained' })])}
        filters={{}}
      />,
    );
    expect(screen.getByText('contained')).toBeInTheDocument();
  });

  it('shows overdue alert when incidents are overdue', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([makeIncident({ is_overdue: true, is_notified: false })])}
        filters={{}}
      />,
    );
    // "overdue" appears in both the alert banner and the OVERDUE label in the table row
    expect(screen.getAllByText(/overdue/i).length).toBeGreaterThanOrEqual(1);
  });

  it('does not show overdue alert when no overdue incidents', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([makeIncident({ is_overdue: false })])}
        filters={{}}
      />,
    );
    // Should not show the destructive alert banner (only the OVERDUE label in table row might exist)
    // Count: the alert title should not be in the document
    expect(screen.queryByText(/breach incident.*overdue/i)).not.toBeInTheDocument();
  });

  it('does not show overdue alert when overdue but already notified', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([makeIncident({ is_overdue: true, is_notified: true })])}
        filters={{}}
      />,
    );
    expect(screen.queryByText(/1 breach incident.*overdue/i)).not.toBeInTheDocument();
  });

  it('shows OVERDUE label in row when is_overdue and not notified', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([makeIncident({ is_overdue: true, is_notified: false })])}
        filters={{}}
      />,
    );
    expect(screen.getByText('OVERDUE')).toBeInTheDocument();
  });

  it('shows empty state when no incidents', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([])} filters={{}} />,
    );
    expect(screen.getByText('No breach incidents')).toBeInTheDocument();
  });

  it('shows affected count', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([makeIncident({ affected_count: 1500 })])}
        filters={{}}
      />,
    );
    expect(screen.getByText('1500')).toBeInTheDocument();
  });

  it('shows total count in description', () => {
    render(
      <BreachIncidentsIndex
        incidents={{ ...makePagination([makeIncident()]), total: 7 }}
        filters={{}}
      />,
    );
    expect(screen.getByText(/Total: 7/)).toBeInTheDocument();
  });

  it('renders incident ID with # prefix', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([makeIncident({ id: 42 })])} filters={{}} />,
    );
    expect(screen.getByText('#42')).toBeInTheDocument();
  });

  it('renders View button for each incident', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([makeIncident()])} filters={{}} />,
    );
    expect(screen.getByRole('button', { name: 'View' })).toBeInTheDocument();
  });

  it('renders Export CSV link', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([])} filters={{}} />,
    );
    expect(screen.getByRole('link', { name: /Export CSV/ })).toBeInTheDocument();
  });

  it('renders Refresh button', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([])} filters={{}} />,
    );
    expect(screen.getByRole('button', { name: /Refresh/ })).toBeInTheDocument();
  });

  it('renders multiple incidents', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([
          makeIncident({ id: 1, description: 'First breach' }),
          makeIncident({ id: 2, description: 'Second breach' }),
        ])}
        filters={{}}
      />,
    );
    expect(screen.getByText('First breach')).toBeInTheDocument();
    expect(screen.getByText('Second breach')).toBeInTheDocument();
  });

  it('selecting an incident shows bulk action bar', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([makeIncident({ id: 1 })])} filters={{}} />,
    );
    fireEvent.click(screen.getByRole('checkbox', { name: /Select incident #1/ }));
    expect(screen.getByText(/1 incident\(s\) selected/)).toBeInTheDocument();
  });

  it('Clear button in bulk bar removes selection', () => {
    render(
      <BreachIncidentsIndex incidents={makePagination([makeIncident({ id: 1 })])} filters={{}} />,
    );
    fireEvent.click(screen.getByRole('checkbox', { name: /Select incident #1/ }));
    expect(screen.getByText(/1 incident\(s\) selected/)).toBeInTheDocument();
    fireEvent.click(screen.getByRole('button', { name: 'Clear' }));
    expect(screen.queryByText(/incident\(s\) selected/)).not.toBeInTheDocument();
  });

  it('Select all checkbox selects all incidents on page', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([
          makeIncident({ id: 1, description: 'Breach A' }),
          makeIncident({ id: 2, description: 'Breach B' }),
        ])}
        filters={{}}
      />,
    );
    fireEvent.click(screen.getByRole('checkbox', { name: 'Select all' }));
    // Independently computed: 2 incidents → 2 selected
    expect(screen.getByText('2 incident(s) selected')).toBeInTheDocument();
  });

  it('Select all then click again deselects all', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([
          makeIncident({ id: 1, description: 'Breach A' }),
          makeIncident({ id: 2, description: 'Breach B' }),
        ])}
        filters={{}}
      />,
    );
    const selectAll = screen.getByRole('checkbox', { name: 'Select all' });
    fireEvent.click(selectAll);
    expect(screen.getByText('2 incident(s) selected')).toBeInTheDocument();
    fireEvent.click(selectAll);
    expect(screen.queryByText(/incident\(s\) selected/)).not.toBeInTheDocument();
  });

  it('shows singular "incident" in overdue alert when exactly 1 is overdue', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([
          makeIncident({ id: 1, is_overdue: true, is_notified: false }),
          makeIncident({ id: 2, is_overdue: true, is_notified: true }), // notified → excluded from count
        ])}
        filters={{}}
      />,
    );
    // Independently: only id=1 counts (overdue && !notified) → count=1 → singular
    expect(screen.getByText('1 breach incident overdue')).toBeInTheDocument();
  });

  it('shows plural "incidents" in overdue alert when more than 1 are overdue', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([
          makeIncident({ id: 1, is_overdue: true, is_notified: false }),
          makeIncident({ id: 2, is_overdue: true, is_notified: false }),
        ])}
        filters={{}}
      />,
    );
    // Independently: both count → 2 → plural
    expect(screen.getByText('2 breach incidents overdue')).toBeInTheDocument();
  });

  it('shows notified badge with outline variant for notified incidents', () => {
    render(
      <BreachIncidentsIndex
        incidents={makePagination([makeIncident({ is_notified: true, status: 'notified' })])}
        filters={{}}
      />,
    );
    // The "notified" status badge should be in the document
    expect(screen.getByText('notified')).toBeInTheDocument();
  });

  it('renders search input with correct label', () => {
    render(<BreachIncidentsIndex incidents={makePagination([])} filters={{}} />);
    expect(screen.getByRole('textbox', { name: /Search breach incidents/ })).toBeInTheDocument();
  });
});
