import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import {
  UserPresence,
  CollaborativeField,
  AwarenessIndicator,
  ChangeHistory
} from '../components';

// Mock user data
const mockUsers = [
  {
    id: 'user1',
    name: 'Alice Johnson',
    email: 'alice@example.com',
    color: '#FF6B6B',
    cursor: { field: 'title', position: 5 }
  },
  {
    id: 'user2',
    name: 'Bob Smith',
    email: 'bob@example.com',
    color: '#4ECDC4'
  },
  {
    id: 'user3',
    name: 'Carol Davis',
    email: 'carol@example.com',
    color: '#45B7D1'
  }
];

const mockAwareness = [
  {
    userId: 'user1',
    userName: 'Alice Johnson',
    color: '#FF6B6B',
    section: 'test-section',
    activity: 'editing' as const,
    lastActivity: new Date()
  }
];

const mockChanges = [
  {
    id: 'change-1',
    userId: 'user1',
    userName: 'Alice Johnson',
    timestamp: new Date(Date.now() - 5 * 60 * 1000),
    field: 'title',
    oldValue: 'Old Title',
    newValue: 'New Title',
    type: 'update' as const,
    metadata: { source: 'ui' }
  },
  {
    id: 'change-2',
    userId: 'user2',
    userName: 'Bob Smith',
    timestamp: new Date(Date.now() - 15 * 60 * 1000),
    field: 'status',
    oldValue: 'pending',
    newValue: 'in-progress',
    type: 'update' as const,
    metadata: { source: 'api' }
  }
];

describe('Collaboration Components', () => {
  describe('UserPresence', () => {
    test('renders user avatars correctly', () => {
      render(<UserPresence users={mockUsers} />);
      
      expect(screen.getByText('AJ')).toBeInTheDocument(); // Alice's initials
      expect(screen.getByText('BS')).toBeInTheDocument(); // Bob's initials
      expect(screen.getByText('CD')).toBeInTheDocument(); // Carol's initials
    });

    test('shows typing indicator for users with cursors', () => {
      render(<UserPresence users={mockUsers} showCursors={true} />);
      
      // Should show typing indicator for user1 who has cursor
      const typingIndicators = document.querySelectorAll('.user-presence__typing-indicator');
      expect(typingIndicators).toHaveLength(1);
    });

    test('limits displayed users when maxDisplay is set', () => {
      render(<UserPresence users={mockUsers} maxDisplay={2} />);
      
      // Should show 2 users + "more" indicator
      const moreIndicator = screen.getByText('+1');
      expect(moreIndicator).toBeInTheDocument();
    });

    test('displays user names on hover', () => {
      render(<UserPresence users={mockUsers} />);
      
      const userAvatar = screen.getByText('AJ').closest('.user-presence__item');
      expect(userAvatar).toHaveAttribute('title', 'Alice Johnson (alice@example.com)');
    });
  });

  describe('CollaborativeField', () => {
    const defaultProps = {
      fieldName: 'title',
      value: 'Test Value',
      onChange: jest.fn(),
      onCursorChange: jest.fn(),
      cursors: []
    };

    beforeEach(() => {
      jest.clearAllMocks();
    });

    test('renders input field correctly', () => {
      render(<CollaborativeField {...defaultProps} />);
      
      const input = screen.getByDisplayValue('Test Value');
      expect(input).toBeInTheDocument();
    });

    test('renders textarea when multiline is true', () => {
      render(<CollaborativeField {...defaultProps} multiline={true} />);
      
      const textarea = screen.getByDisplayValue('Test Value');
      expect(textarea.tagName).toBe('TEXTAREA');
    });

    test('calls onChange when value changes', () => {
      render(<CollaborativeField {...defaultProps} />);
      
      const input = screen.getByDisplayValue('Test Value');
      fireEvent.change(input, { target: { value: 'New Value' } });
      
      expect(defaultProps.onChange).toHaveBeenCalledWith('New Value');
    });

    test('shows placeholder when no value', () => {
      render(
        <CollaborativeField 
          {...defaultProps} 
          value="" 
          placeholder="Enter text..."
        />
      );
      
      const input = screen.getByPlaceholderText('Enter text...');
      expect(input).toBeInTheDocument();
    });

    test('shows cursor indicators', () => {
      const cursors = [
        {
          userId: 'user1',
          field: 'title',
          position: 5,
          color: '#FF6B6B',
          userName: 'Alice'
        }
      ];

      render(<CollaborativeField {...defaultProps} cursors={cursors} />);
      
      // Cursor indicator should be present (implementation-specific)
      const field = screen.getByDisplayValue('Test Value').parentElement;
      expect(field).toBeInTheDocument();
    });

    test('is disabled when disabled prop is true', () => {
      render(<CollaborativeField {...defaultProps} disabled={true} />);
      
      const input = screen.getByDisplayValue('Test Value');
      expect(input).toBeDisabled();
    });
  });

  describe('AwarenessIndicator', () => {
    test('renders awareness indicator with users', () => {
      render(
        <AwarenessIndicator
          section="test-section"
          awareness={mockAwareness}
          currentUserId="current-user"
        />
      );
      
      // Should show user avatar
      const avatar = screen.getByText('A'); // Alice's initial
      expect(avatar).toBeInTheDocument();
    });

    test('does not render when no awareness data', () => {
      const { container } = render(
        <AwarenessIndicator
          section="test-section"
          awareness={[]}
          currentUserId="current-user"
        />
      );
      
      expect(container.firstChild).toBeNull();
    });

    test('shows tooltip on hover', async () => {
      render(
        <AwarenessIndicator
          section="test-section"
          awareness={mockAwareness}
          currentUserId="current-user"
        />
      );
      
      const indicator = document.querySelector('.awareness-indicator');
      if (indicator) {
        fireEvent.mouseEnter(indicator);
        
        await waitFor(() => {
          expect(screen.getByText('Active in this section')).toBeInTheDocument();
        });
      }
    });
  });

  describe('ChangeHistory', () => {
    test('renders change history list', () => {
      render(<ChangeHistory changes={mockChanges} />);
      
      expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
      expect(screen.getByText('Bob Smith')).toBeInTheDocument();
      expect(screen.getByText('Title')).toBeInTheDocument();
      expect(screen.getByText('Status')).toBeInTheDocument();
    });

    test('shows filter inputs', () => {
      render(<ChangeHistory changes={mockChanges} />);
      
      expect(screen.getByPlaceholderText('Filter by field...')).toBeInTheDocument();
      expect(screen.getByPlaceholderText('Filter by user...')).toBeInTheDocument();
    });

    test('calls onRevert when revert button is clicked', () => {
      const onRevert = jest.fn();
      render(<ChangeHistory changes={mockChanges} onRevert={onRevert} />);
      
      const revertButtons = screen.getAllByTitle(/Revert this change/i);
      fireEvent.click(revertButtons[0]);
      
      expect(onRevert).toHaveBeenCalledWith('change-1');
    });

    test('allows change selection for comparison', () => {
      const onCompare = jest.fn();
      render(<ChangeHistory changes={mockChanges} onCompare={onCompare} />);
      
      const checkboxes = screen.getAllByRole('checkbox');
      fireEvent.click(checkboxes[0]);
      fireEvent.click(checkboxes[1]);
      
      expect(onCompare).toHaveBeenCalledWith('change-1', 'change-2');
    });

    test('expands change details when clicked', () => {
      render(<ChangeHistory changes={mockChanges} showDiff={true} />);
      
      const changeItem = screen.getByText('Alice Johnson').closest('.change-history__item-header');
      if (changeItem) {
        fireEvent.click(changeItem);
        
        // Should show diff content
        expect(screen.getByText('Old:')).toBeInTheDocument();
        expect(screen.getByText('New:')).toBeInTheDocument();
      }
    });

    test('filters changes by field', () => {
      render(<ChangeHistory changes={mockChanges} />);
      
      const fieldFilter = screen.getByPlaceholderText('Filter by field...');
      fireEvent.change(fieldFilter, { target: { value: 'title' } });
      
      // Should still show Alice's change (title change)
      expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
    });

    test('filters changes by user', () => {
      render(<ChangeHistory changes={mockChanges} />);
      
      const userFilter = screen.getByPlaceholderText('Filter by user...');
      fireEvent.change(userFilter, { target: { value: 'Alice' } });
      
      // Should show Alice's change
      expect(screen.getByText('Alice Johnson')).toBeInTheDocument();
    });

    test('shows empty state when no changes', () => {
      render(<ChangeHistory changes={[]} />);
      
      expect(screen.getByText('No changes found')).toBeInTheDocument();
    });

    test('limits displayed changes', () => {
      const manyChanges = Array(100).fill(null).map((_, i) => ({
        ...mockChanges[0],
        id: `change-${i}`,
        timestamp: new Date(Date.now() - i * 60 * 1000)
      }));

      render(<ChangeHistory changes={manyChanges} maxDisplay={2} />);
      
      // Should only render 2 changes
      const changeItems = document.querySelectorAll('.change-history__item');
      expect(changeItems).toHaveLength(2);
    });
  });
});