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

import Team from './Team';

const { mockPost, mockPatch, mockDelete } = vi.hoisted(() => ({
  mockPost: vi.fn(),
  mockPatch: vi.fn(),
  mockDelete: vi.fn(),
}));
let mockInviteErrors: Record<string, string> = {};
let mockProcessing = false;

vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    Head: ({ title }: { title: string }) => <title>{title}</title>,
    useForm: vi.fn(() => ({
      data: { email: '', role: 'viewer' },
      setData: vi.fn(),
      post: mockPost,
      patch: mockPatch,
      reset: vi.fn(),
      processing: mockProcessing,
      errors: mockInviteErrors,
    })),
    router: {
      delete: mockDelete,
      visit: vi.fn(),
      post: vi.fn(),
      patch: vi.fn(),
    },
    usePage: vi.fn(() => ({
      props: {
        auth: { user: { id: 1, name: 'Owner' } },
        errors: {},
        flash: {},
        features: {},
        sites: [],
        limits: null,
        ai_defaults: {},
        notifications_unread_count: 0,
      },
    })),
  };
});

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

const defaultSite = { id: 1, name: 'Acme Corp' };
const defaultRoles = ['viewer', 'editor', 'admin'];

const member1 = {
  id: 10,
  user: { id: 2, name: 'Alice Smith', email: 'alice@example.com' },
  role: 'editor' as const,
  accepted_at: '2024-01-15T10:00:00Z',
};

const pendingInvite = {
  id: 20,
  user: { id: 3, name: 'Bob Jones', email: 'bob@example.com' },
  role: 'viewer' as const,
  token_expires_at: '2024-02-01T00:00:00Z',
  invited_by: { id: 1, name: 'Owner', email: 'owner@example.com' },
};

describe('Sites/Settings/Team', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockInviteErrors = {};
    mockProcessing = false;
    vi.stubGlobal(
      'route',
      vi.fn((name: string, _params?: unknown) => {
        if (name === 'site-members.store') return '/sites/1/settings/team';
        if (name === 'site-members.update') return '/sites/1/settings/team/10';
        if (name === 'site-members.destroy') return '/sites/1/settings/team/10';
        return '/sites/1/settings/team';
      }),
    );
  });

  // ── Rendering ──

  describe('rendering', () => {
    it('renders the page title with site name', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(document.querySelector('title')).toHaveTextContent('Team — Acme Corp');
    });

    it('renders the heading', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByRole('heading', { name: /team members/i, level: 1 })).toBeInTheDocument();
    });

    it('renders the site name in description', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByText('Acme Corp', { selector: 'strong' })).toBeInTheDocument();
    });

    it('renders inside DashboardLayout', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByTestId('dashboard-layout')).toBeInTheDocument();
    });
  });

  // ── Empty state ──

  describe('empty state', () => {
    it('shows empty state message when no members', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByText(/no team members yet/i)).toBeInTheDocument();
    });

    it('does not show pending section when no pending invitations', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.queryByText(/pending invitations/i)).not.toBeInTheDocument();
    });
  });

  // ── Members list ──

  describe('members list', () => {
    it('renders member name and email', () => {
      render(<Team site={defaultSite} members={[member1]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByText('Alice Smith')).toBeInTheDocument();
      expect(screen.getByText('alice@example.com')).toBeInTheDocument();
    });

    it('renders role badge for member', () => {
      render(<Team site={defaultSite} members={[member1]} pending={[]} roles={defaultRoles} />);

      // Badge renders capitalized role (also appears in SelectTrigger, so use getAllByText)
      expect(screen.getAllByText('Editor').length).toBeGreaterThan(0);
    });

    it('renders remove button for each member', () => {
      render(<Team site={defaultSite} members={[member1]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByRole('button', { name: /remove/i })).toBeInTheDocument();
    });

    it('shows confirmation buttons after clicking remove', () => {
      render(<Team site={defaultSite} members={[member1]} pending={[]} roles={defaultRoles} />);

      fireEvent.click(screen.getByRole('button', { name: /remove/i }));

      expect(screen.getByRole('button', { name: /confirm/i })).toBeInTheDocument();
      expect(screen.getByRole('button', { name: /cancel/i })).toBeInTheDocument();
    });

    it('hides confirmation buttons after clicking cancel', () => {
      render(<Team site={defaultSite} members={[member1]} pending={[]} roles={defaultRoles} />);

      fireEvent.click(screen.getByRole('button', { name: /remove/i }));
      fireEvent.click(screen.getByRole('button', { name: /cancel/i }));

      expect(screen.queryByRole('button', { name: /confirm/i })).not.toBeInTheDocument();
      expect(screen.getByRole('button', { name: /remove/i })).toBeInTheDocument();
    });

    it('calls router.delete when confirm is clicked', () => {
      render(<Team site={defaultSite} members={[member1]} pending={[]} roles={defaultRoles} />);

      fireEvent.click(screen.getByRole('button', { name: /remove/i }));
      fireEvent.click(screen.getByRole('button', { name: /confirm/i }));

      expect(mockDelete).toHaveBeenCalledWith(
        expect.stringContaining('team'),
        expect.objectContaining({ onFinish: expect.any(Function) }),
      );
    });
  });

  // ── Pending invitations ──

  describe('pending invitations', () => {
    it('renders pending invitations section when there are pending invites', () => {
      render(
        <Team site={defaultSite} members={[]} pending={[pendingInvite]} roles={defaultRoles} />,
      );

      expect(screen.getByText(/pending invitations/i)).toBeInTheDocument();
    });

    it('renders pending invite email', () => {
      render(
        <Team site={defaultSite} members={[]} pending={[pendingInvite]} roles={defaultRoles} />,
      );

      expect(screen.getByText('bob@example.com')).toBeInTheDocument();
    });

    it('renders revoke button for pending invite', () => {
      render(
        <Team site={defaultSite} members={[]} pending={[pendingInvite]} roles={defaultRoles} />,
      );

      expect(screen.getByRole('button', { name: /revoke/i })).toBeInTheDocument();
    });
  });

  // ── Invite form ──

  describe('invite form', () => {
    it('renders the Invite Member section heading', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByRole('heading', { name: /invite member/i })).toBeInTheDocument();
    });

    it('renders email address input', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByPlaceholderText(/colleague@example.com/i)).toBeInTheDocument();
    });

    it('renders the Send Invite submit button', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByRole('button', { name: /send invite/i })).toBeInTheDocument();
    });

    it('shows email validation error when present', () => {
      mockInviteErrors = { email: 'The email field is required.' };

      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByText('The email field is required.')).toBeInTheDocument();
    });

    it('calls post when form is submitted', () => {
      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      const form = screen.getByRole('button', { name: /send invite/i }).closest('form')!;
      fireEvent.submit(form);

      expect(mockPost).toHaveBeenCalled();
    });

    it('disables submit button when processing', () => {
      mockProcessing = true;

      render(<Team site={defaultSite} members={[]} pending={[]} roles={defaultRoles} />);

      expect(screen.getByRole('button', { name: /in progress/i })).toBeDisabled();
    });
  });
});
