/**
 * Pack-5 (session c93b3449) R3UXS-008 frontend tests:
 *  - inline Acknowledge button fires router.post(alerts.acknowledge)
 *  - bulk-acknowledge selects multiple alerts then fires router.post(alerts.bulk-acknowledge)
 *  - Unacknowledged count appears in the header when > 0
 */
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi, beforeEach } from 'vitest';

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

import TrafficAlertsIndex, { type Filters } from './Index';

vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    Head: ({ title }: { title: string }) => <title>{title}</title>,
    Link: ({ children, href }: { children: React.ReactNode; href: string }) => (
      <a href={href}>{children}</a>
    ),
    router: {
      visit: vi.fn(),
      reload: vi.fn(),
      get: vi.fn(),
      post: vi.fn(),
      patch: vi.fn(),
      on: vi.fn(() => vi.fn()),
    },
    usePage: () => ({
      props: { plan: 'pro' },
    }),
  };
});

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

vi.mock('@/Components/ui/empty-state', () => {
  type Act = { label: string; href?: string; onClick?: () => void };
  const renderAct = (act: Act) =>
    act.href ? (
      <a href={act.href}>{act.label}</a>
    ) : (
      <button onClick={act.onClick}>{act.label}</button>
    );
  return {
    EmptyState: ({
      title,
      description,
      action,
      primaryAction,
      retryAction,
    }: {
      title: string;
      description?: string;
      action?: React.ReactNode;
      primaryAction?: Act;
      retryAction?: Act;
    }) => (
      <div data-testid="empty-state">
        <h3>{title}</h3>
        {description && <p>{description}</p>}
        {action}
        {action
          ? null
          : primaryAction
            ? renderAct(primaryAction)
            : retryAction
              ? renderAct(retryAction)
              : null}
      </div>
    ),
  };
});

const emptyFilters: Filters = {
  severity: null,
  status: null,
  anomaly_type: null,
  start_date: null,
  end_date: null,
  sort_by: null,
};

const baseCounts = {
  total: 2,
  unacknowledged: 2,
  acknowledged: 0,
  dismissed: 0,
  resolved: 0,
  open: 2,
  critical: 0,
  warning: 2,
  info: 0,
};

const makeAlert = (
  id: number,
  status: 'unacknowledged' | 'acknowledged' | 'dismissed' = 'unacknowledged',
) => ({
  id,
  site_id: 1,
  severity: 'warning' as const,
  anomaly_type: 'sudden_drop' as const,
  status,
  page_url: `https://example.com/blog/page-${id}`,
  metrics: {
    clicks_before: 500,
    clicks_after: 250,
    delta_percent: -50.0,
    impressions_before: 5000,
    impressions_after: 3000,
    ctr_before: 0.1,
    ctr_after: 0.083,
    position_before: 5.0,
    position_after: 8.0,
  },
  created_at: '2026-03-10T12:00:00Z',
  acknowledged_at: null,
  dismissed_at: null,
  finding_id: 1,
  analysis_run_id: 1,
});

const mockSite = { id: '1', name: 'Test Site', domain: 'example.com' };

const twoAlerts = {
  data: [makeAlert(10), makeAlert(20)],
  links: [] as Array<{ url: string | null; label: string; active: boolean }>,
  current_page: 1,
  last_page: 1,
};

describe('TrafficAlerts/Index – pack-5 R3UXS-008', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('Unacked count header readout (R3UXS-008/R3UXS-016)', () => {
    it('shows "Unacked" label in page header readouts when count > 0', () => {
      render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={twoAlerts}
          filters={emptyFilters}
          counts={{ ...baseCounts, unacknowledged: 2 }}
          has_completed_analysis={true}
        />,
      );

      // Header readout uses abbreviated "Unacked" label (not full "Unacknowledged")
      expect(screen.getByText('Unacked')).toBeInTheDocument();
    });

    it('renders the header readout section with Unacked label when counts.total > 0', () => {
      const { container } = render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={twoAlerts}
          filters={emptyFilters}
          counts={{ ...baseCounts, unacknowledged: 2 }}
          has_completed_analysis={true}
        />,
      );

      // The EditorialPageHeader should be rendered with the data-testid
      const header = container.querySelector('[data-testid="page-header"]');
      expect(header).toBeInTheDocument();
      // "Unacked" readout label must appear in the header
      const headerText = header?.textContent ?? '';
      expect(headerText).toContain('Unacked');
    });
  });

  describe('Inline Acknowledge button (aria-label: "Acknowledge this alert")', () => {
    it('fires router.post to an acknowledge URL when the Acknowledge button is clicked', async () => {
      const user = userEvent.setup();
      render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={{
            data: [makeAlert(10, 'unacknowledged')],
            links: [],
            current_page: 1,
            last_page: 1,
          }}
          filters={emptyFilters}
          counts={{ ...baseCounts, total: 1, unacknowledged: 1, warning: 1, open: 1 }}
          has_completed_analysis={true}
        />,
      );

      // The button has aria-label="Acknowledge this alert" (takes precedence over text)
      const ackButton = screen.getByRole('button', { name: /acknowledge this alert/i });
      await user.click(ackButton);

      const postCalls = vi.mocked(router.post).mock.calls;
      expect(postCalls.length).toBeGreaterThanOrEqual(1);

      // URL should contain 'acknowledge' (not 'bulk-acknowledge')
      const url = postCalls[0][0] as string;
      expect(url).toContain('acknowledge');
      expect(url).not.toContain('bulk');
    });

    it('does not show Acknowledge button for already-acknowledged alerts', () => {
      render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={{
            data: [makeAlert(10, 'acknowledged')],
            links: [],
            current_page: 1,
            last_page: 1,
          }}
          filters={emptyFilters}
          counts={{ ...baseCounts, total: 1, unacknowledged: 0, acknowledged: 1 }}
          has_completed_analysis={true}
        />,
      );

      // The inline Acknowledge button should not be rendered for acknowledged alerts
      expect(
        screen.queryByRole('button', { name: /acknowledge this alert/i }),
      ).not.toBeInTheDocument();
    });
  });

  describe('Bulk acknowledge', () => {
    it('shows bulk action bar when alerts are selected via select-all', async () => {
      const user = userEvent.setup();
      render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={twoAlerts}
          filters={emptyFilters}
          counts={baseCounts}
          has_completed_analysis={true}
        />,
      );

      // Select-all checkbox in the header row above the list
      const selectAllCheckbox = screen.getByRole('checkbox', {
        name: /select all alerts on this page/i,
      });
      await user.click(selectAllCheckbox);

      // Bulk action bar should now appear — "Acknowledge 2" and "Dismiss 2"
      expect(screen.getByRole('button', { name: /Acknowledge 2/i })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /Dismiss 2/i })).toBeInTheDocument();
    });

    it('fires router.post(alerts.bulk-acknowledge) with selected IDs when Acknowledge N is clicked', async () => {
      const user = userEvent.setup();
      render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={twoAlerts}
          filters={emptyFilters}
          counts={baseCounts}
          has_completed_analysis={true}
        />,
      );

      const selectAllCheckbox = screen.getByRole('checkbox', {
        name: /select all alerts on this page/i,
      });
      await user.click(selectAllCheckbox);

      const bulkAckButton = screen.getByRole('button', { name: /Acknowledge 2/i });
      await user.click(bulkAckButton);

      const postCalls = vi.mocked(router.post).mock.calls;
      expect(postCalls.length).toBeGreaterThanOrEqual(1);

      // The last post call should be to bulk-acknowledge
      const lastCall = postCalls[postCalls.length - 1];
      expect((lastCall[0] as string)).toContain('bulk-acknowledge');
      // alert_ids are ULID public_id strings (AMEND ENGR-013 / R8UXB-003: number→NaN, must be strings)
      expect((lastCall[1] as { alert_ids: string[] }).alert_ids).toContain('10');
      expect((lastCall[1] as { alert_ids: string[] }).alert_ids).toContain('20');
    });

    it('fires router.post(alerts.bulk-dismiss) with selected IDs when Dismiss N is clicked', async () => {
      const user = userEvent.setup();
      render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={twoAlerts}
          filters={emptyFilters}
          counts={baseCounts}
          has_completed_analysis={true}
        />,
      );

      const selectAllCheckbox = screen.getByRole('checkbox', {
        name: /select all alerts on this page/i,
      });
      await user.click(selectAllCheckbox);

      const bulkDismissButton = screen.getByRole('button', { name: /Dismiss 2/i });
      await user.click(bulkDismissButton);

      const postCalls = vi.mocked(router.post).mock.calls;
      expect(postCalls.length).toBeGreaterThanOrEqual(1);

      const lastCall = postCalls[postCalls.length - 1];
      expect((lastCall[0] as string)).toContain('bulk-dismiss');
      // alert_ids are ULID public_id strings (AMEND ENGR-013 / R8UXB-003: number→NaN, must be strings)
      expect((lastCall[1] as { alert_ids: string[] }).alert_ids).toContain('10');
      expect((lastCall[1] as { alert_ids: string[] }).alert_ids).toContain('20');
    });

    it('clears selection when Clear selection button is clicked', async () => {
      const user = userEvent.setup();
      render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={twoAlerts}
          filters={emptyFilters}
          counts={baseCounts}
          has_completed_analysis={true}
        />,
      );

      const selectAllCheckbox = screen.getByRole('checkbox', {
        name: /select all alerts on this page/i,
      });
      await user.click(selectAllCheckbox);

      // Bulk bar appears
      expect(screen.getByRole('button', { name: /Acknowledge 2/i })).toBeInTheDocument();

      const clearSelBtn = screen.getByRole('button', { name: /clear selection/i });
      await user.click(clearSelBtn);

      // Bulk bar disappears after clearing
      expect(screen.queryByRole('button', { name: /Acknowledge 2/i })).not.toBeInTheDocument();
    });

    it('selecting individual alert checkbox adds it to the selection', async () => {
      const user = userEvent.setup();
      render(
        <TrafficAlertsIndex
          site={mockSite}
          alerts={twoAlerts}
          filters={emptyFilters}
          counts={baseCounts}
          has_completed_analysis={true}
        />,
      );

      // Select only the first alert (id=10) via its per-row checkbox
      // aria-label is "Select alert for https://example.com/blog/page-10"
      const firstCheckbox = screen.getByRole('checkbox', {
        name: /select alert for.*page-10/i,
      });
      await user.click(firstCheckbox);

      // Bulk bar should show 1 selected
      expect(screen.getByRole('button', { name: /Acknowledge 1/i })).toBeInTheDocument();
    });
  });
});
