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

import type { AdminLimitPoliciesIndexProps } 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/limit-policies',
      props: {
        auth: { user: { name: 'Admin', email: 'admin@test.com', is_admin: true } },
        features: {
          billing: false,
          socialAuth: false,
          emailVerification: true,
          apiTokens: true,
          userSettings: true,
          notifications: false,
          admin: true,
        },
      },
    })),
    Link: ({
      children,
      href,
      ...rest
    }: {
      children: React.ReactNode;
      href: string;
      className?: string;
    }) => (
      <a href={href} {...rest}>
        {children}
      </a>
    ),
    useForm: vi.fn(() => ({
      data: { key: '', value: 0, user_id: '' },
      setData: vi.fn(),
      post: vi.fn(),
      delete: vi.fn(),
      processing: false,
      errors: {},
    })),
    router: {
      patch: vi.fn(),
      delete: vi.fn(),
      post: vi.fn(),
      get: vi.fn(),
      on: vi.fn(() => vi.fn()),
    },
  };
});

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

import LimitPoliciesIndex from './Index';

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

const makePolicy = (overrides = {}) => ({
  id: 1,
  scope: 'user',
  scope_id: 5,
  scope_label: 'Alice Example (user)',
  user_id: 5,
  user_name: 'Alice Example',
  user_email: 'alice@example.com',
  site_domain: null,
  key: 'max_sites',
  value: 10,
  config_default: 3,
  created_at: '2026-01-01T00:00:00Z',
  ...overrides,
});

const defaultProps: AdminLimitPoliciesIndexProps = {
  policies: makePagination([makePolicy()]),
  limit_keys: ['max_sites', 'max_drafts_per_month', 'max_recommendations'],
  filters: {},
};

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

  it('renders the Limit Policies heading', () => {
    render(<LimitPoliciesIndex {...defaultProps} />);
    expect(screen.getByRole('heading', { name: /Limit Policies/i, level: 1 })).toBeInTheDocument();
  });

  it('renders user name in policy row', () => {
    render(<LimitPoliciesIndex {...defaultProps} />);
    expect(screen.getByText('Alice Example')).toBeInTheDocument();
  });

  it('renders limit key in row', () => {
    render(<LimitPoliciesIndex {...defaultProps} />);
    expect(screen.getByText('max_sites')).toBeInTheDocument();
  });

  it('renders overridden value in row', () => {
    render(<LimitPoliciesIndex {...defaultProps} />);
    expect(screen.getByText('10')).toBeInTheDocument();
  });

  it('renders config default value', () => {
    render(<LimitPoliciesIndex {...defaultProps} />);
    expect(screen.getByText('3')).toBeInTheDocument();
  });

  it('shows empty state when no policies', () => {
    render(
      <LimitPoliciesIndex
        {...defaultProps}
        policies={makePagination([])}
      />,
    );
    expect(screen.getByText('No limit overrides found')).toBeInTheDocument();
  });

  it('renders the Override actions button for existing policies', () => {
    render(<LimitPoliciesIndex {...defaultProps} />);
    // Each policy row has an "Override actions" dropdown trigger
    expect(screen.getByRole('button', { name: /Override actions/i })).toBeInTheDocument();
  });

  // ADMFE-02: ConfirmDialog must stay open on error (ref-bridge reject pattern)
  describe('ADMFE-02: bulk delete dialog stays open on error', () => {
    it('keeps bulk-delete dialog open when router.delete calls onError', async () => {
      const { router } = await import('@inertiajs/react');
      const user = userEvent.setup();

      vi.mocked(router.delete).mockImplementation((_url, opts: Record<string, unknown> = {}) => {
        const onError = opts.onError as ((errors: Record<string, string>) => void) | undefined;
        onError?.({ server: 'Delete failed' });
        const onFinish = opts.onFinish as (() => void) | undefined;
        onFinish?.();
      });

      render(<LimitPoliciesIndex {...defaultProps} />);

      // Click the row checkbox to select the policy
      const checkbox = screen.getByRole('checkbox', { name: /select override/i });
      await user.click(checkbox);

      // "Delete Selected" button should now appear
      const deleteSelectedBtn = screen.getByRole('button', { name: /delete selected/i });
      await user.click(deleteSelectedBtn);

      // Bulk delete dialog should open
      expect(screen.getByRole('alertdialog')).toBeInTheDocument();

      // Click the confirm button inside the dialog
      const confirmBtn = screen.getAllByRole('button').find(
        (b) => b.closest('[role="alertdialog"]') && /delete/i.test(b.textContent ?? ''),
      );
      if (confirmBtn) await user.click(confirmBtn);

      // Dialog MUST remain open — onError caused the Promise to reject
      expect(screen.getByRole('alertdialog')).toBeInTheDocument();
    });
  });

  // ADMFE-R15-02: user link must resolve a real user_id not 'undefined'
  it('ADMFE-R15-02: user-scoped row renders /admin/users/{user_id} link with real id', () => {
    render(
      <LimitPoliciesIndex
        {...defaultProps}
        policies={makePagination([makePolicy({ user_id: 5, scope: 'user', scope_label: 'Alice Example' })])}
      />,
    );
    const link = screen.getByRole('link', { name: 'Alice Example' });
    expect(link).toHaveAttribute('href', '/admin/users/5');
    expect(link.getAttribute('href')).not.toContain('undefined');
    expect(link.getAttribute('href')).not.toContain('null');
  });

  it('ADMFE-R15-02: site-scoped row renders scope_label as plain text, no user link', () => {
    render(
      <LimitPoliciesIndex
        {...defaultProps}
        policies={makePagination([makePolicy({
          user_id: null,
          scope: 'site',
          scope_label: 'site:1',
          user_name: null,
          user_email: null,
          site_domain: 'example.com',
        })])}
      />,
    );
    // No link rendered for site-scoped rows
    expect(screen.queryByRole('link', { name: /site:1/i })).not.toBeInTheDocument();
    // Plain text scope_label is shown
    expect(screen.getByText('site:1')).toBeInTheDocument();
  });
});
