import { test, expect, Page, BrowserContext } from '@playwright/test';

// Test data
const testEmail1 = `user+chat1-${Date.now()}@lab.veza`;
const testEmail2 = `user+chat2-${Date.now()}@lab.veza`;
const testPassword = `V3za!chat-${Date.now()}`;

// Helper to register and login
async function registerAndLogin(page: Page, email: string, password: string) {
  await page.goto('/register');
  await page.fill('input[type="email"]', email);
  await page.fill('input[type="password"]', password);
  
  const confirmField = page.locator('input[name="confirmPassword"]');
  if (await confirmField.isVisible()) {
    await confirmField.fill(password);
  }
  
  await page.locator('button[type="submit"]').click();
  await expect(page).toHaveURL(/\/(dashboard|home|app|chat)/, { timeout: 10000 });
}

test.describe('Chat Functionality', () => {
  let context1: BrowserContext;
  let context2: BrowserContext;
  let page1: Page;
  let page2: Page;

  test.beforeAll(async ({ browser }) => {
    // Create two browser contexts for two users
    context1 = await browser.newContext();
    context2 = await browser.newContext();
    
    page1 = await context1.newPage();
    page2 = await context2.newPage();
    
    // Register both users
    await registerAndLogin(page1, testEmail1, testPassword);
    await registerAndLogin(page2, testEmail2, testPassword);
  });

  test.afterAll(async () => {
    await context1.close();
    await context2.close();
  });

  test('should load chat interface', async () => {
    await page1.goto('/chat');
    
    // Check main chat elements
    await expect(page1.locator('[data-testid="chat-container"], .chat-container, #chat')).toBeVisible();
    await expect(page1.locator('[data-testid="message-input"], input[placeholder*="message"], textarea[placeholder*="message"]')).toBeVisible();
    await expect(page1.locator('[data-testid="send-button"], button:has-text("Send")')).toBeVisible();
    
    // Check for rooms/channels list
    await expect(page1.locator('[data-testid="rooms-list"], .rooms-list, .channels-list')).toBeVisible();
  });

  test('should join default room', async () => {
    await page1.goto('/chat');
    
    // Look for general/default room
    const generalRoom = page1.locator('text=/general|default|lobby/i');
    
    if (await generalRoom.isVisible()) {
      await generalRoom.click();
      
      // Should show room is active
      await expect(generalRoom).toHaveClass(/active|selected/, { timeout: 5000 });
    }
    
    // Should show room name in header
    await expect(page1.locator('h1, h2, .room-name').filter({ hasText: /general|default|lobby/i })).toBeVisible();
  });

  test('should send and receive messages', async () => {
    // Both users go to chat
    await page1.goto('/chat');
    await page2.goto('/chat');
    
    // Join same room
    const room = 'general';
    await page1.locator(`text=${room}`).click();
    await page2.locator(`text=${room}`).click();
    
    // User 1 sends a message
    const testMessage = `Test message ${Date.now()}`;
    await page1.fill('[data-testid="message-input"], input[placeholder*="message"]', testMessage);
    await page1.locator('[data-testid="send-button"], button:has-text("Send")').click();
    
    // Message should appear for user 1
    await expect(page1.locator(`text="${testMessage}"`)).toBeVisible({ timeout: 5000 });
    
    // Message should appear for user 2
    await expect(page2.locator(`text="${testMessage}"`)).toBeVisible({ timeout: 5000 });
  });

  test('should show message metadata', async () => {
    await page1.goto('/chat');
    
    const testMessage = `Metadata test ${Date.now()}`;
    await page1.fill('[data-testid="message-input"]', testMessage);
    await page1.locator('[data-testid="send-button"]').click();
    
    // Find the message container
    const messageContainer = page1.locator(`text="${testMessage}"`).locator('xpath=ancestor::*[contains(@class, "message")]');
    
    // Should show timestamp
    await expect(messageContainer.locator('time, .timestamp, .message-time')).toBeVisible();
    
    // Should show sender name
    await expect(messageContainer.locator('.sender, .username, .author')).toBeVisible();
  });

  test('should handle emoji in messages', async () => {
    await page1.goto('/chat');
    
    const emojiMessage = `Hello 👋 World 🌍 ${Date.now()}`;
    await page1.fill('[data-testid="message-input"]', emojiMessage);
    await page1.locator('[data-testid="send-button"]').click();
    
    // Emoji should be displayed correctly
    await expect(page1.locator(`text="${emojiMessage}"`)).toBeVisible({ timeout: 5000 });
  });

  test('should show typing indicators', async () => {
    await page1.goto('/chat');
    await page2.goto('/chat');
    
    // User 1 starts typing
    await page1.fill('[data-testid="message-input"]', 'Typing...');
    
    // User 2 should see typing indicator (if implemented)
    const typingIndicator = page2.locator('text=/typing|is typing/i, .typing-indicator');
    
    // This might not be implemented, so we make it optional
    if (await typingIndicator.isVisible({ timeout: 2000 }).catch(() => false)) {
      expect(typingIndicator).toBeTruthy();
    }
  });

  test('should handle message editing', async () => {
    await page1.goto('/chat');
    
    // Send a message
    const originalMessage = `Original ${Date.now()}`;
    await page1.fill('[data-testid="message-input"]', originalMessage);
    await page1.locator('[data-testid="send-button"]').click();
    
    // Wait for message to appear
    const message = page1.locator(`text="${originalMessage}"`);
    await expect(message).toBeVisible();
    
    // Try to edit (right-click or edit button)
    const messageContainer = message.locator('xpath=ancestor::*[contains(@class, "message")]');
    
    // Look for edit option
    await messageContainer.hover();
    const editButton = messageContainer.locator('button:has-text("Edit"), [data-testid="edit-message"]');
    
    if (await editButton.isVisible({ timeout: 2000 }).catch(() => false)) {
      await editButton.click();
      
      // Edit the message
      const editInput = page1.locator('input[value*="Original"], textarea:has-text("Original")');
      await editInput.fill(`Edited ${Date.now()}`);
      await editInput.press('Enter');
      
      // Should show edited indicator
      await expect(messageContainer.locator('text=/edited/i')).toBeVisible();
    }
  });

  test('should handle message deletion', async () => {
    await page1.goto('/chat');
    
    // Send a message
    const deleteMessage = `To delete ${Date.now()}`;
    await page1.fill('[data-testid="message-input"]', deleteMessage);
    await page1.locator('[data-testid="send-button"]').click();
    
    // Wait for message
    const message = page1.locator(`text="${deleteMessage}"`);
    await expect(message).toBeVisible();
    
    // Try to delete
    const messageContainer = message.locator('xpath=ancestor::*[contains(@class, "message")]');
    await messageContainer.hover();
    
    const deleteButton = messageContainer.locator('button:has-text("Delete"), [data-testid="delete-message"]');
    
    if (await deleteButton.isVisible({ timeout: 2000 }).catch(() => false)) {
      await deleteButton.click();
      
      // Confirm if needed
      const confirmButton = page1.locator('button:has-text("Confirm"), button:has-text("Yes")');
      if (await confirmButton.isVisible({ timeout: 1000 }).catch(() => false)) {
        await confirmButton.click();
      }
      
      // Message should be gone or marked as deleted
      await expect(message).not.toBeVisible({ timeout: 5000 });
    }
  });

  test('should load message history', async () => {
    await page1.goto('/chat');
    
    // Send multiple messages
    for (let i = 0; i < 5; i++) {
      await page1.fill('[data-testid="message-input"]', `History message ${i}`);
      await page1.locator('[data-testid="send-button"]').click();
      await page1.waitForTimeout(100); // Small delay between messages
    }
    
    // Reload page
    await page1.reload();
    
    // Messages should still be visible
    for (let i = 0; i < 5; i++) {
      await expect(page1.locator(`text="History message ${i}"`)).toBeVisible();
    }
  });

  test('should handle file uploads in chat', async () => {
    await page1.goto('/chat');
    
    // Look for file upload button
    const uploadButton = page1.locator('button[aria-label="Upload"], [data-testid="upload-file"], input[type="file"]');
    
    if (await uploadButton.isVisible({ timeout: 2000 }).catch(() => false)) {
      // Create a test file
      const buffer = Buffer.from('Test file content');
      await uploadButton.setInputFiles({
        name: 'test.txt',
        mimeType: 'text/plain',
        buffer,
      });
      
      // Should show file in chat
      await expect(page1.locator('text=test.txt')).toBeVisible({ timeout: 5000 });
    }
  });

  test('should handle room switching', async () => {
    await page1.goto('/chat');
    
    // Get list of rooms
    const rooms = await page1.locator('.room-item, [data-testid^="room-"]').all();
    
    if (rooms.length > 1) {
      // Click second room
      await rooms[1].click();
      
      // Should update UI
      await expect(rooms[1]).toHaveClass(/active|selected/);
      
      // Messages should update
      const messagesContainer = page1.locator('.messages, [data-testid="messages-container"]');
      await expect(messagesContainer).toBeVisible();
    }
  });

  test('should handle room creation', async () => {
    await page1.goto('/chat');
    
    // Look for create room button
    const createButton = page1.locator('button:has-text("Create"), button:has-text("New Room"), [data-testid="create-room"]');
    
    if (await createButton.isVisible({ timeout: 2000 }).catch(() => false)) {
      await createButton.click();
      
      // Fill room name
      const roomNameInput = page1.locator('input[placeholder*="room name"], input[name="roomName"]');
      const newRoomName = `Test Room ${Date.now()}`;
      await roomNameInput.fill(newRoomName);
      
      // Submit
      await page1.locator('button:has-text("Create"), button:has-text("Submit")').click();
      
      // New room should appear in list
      await expect(page1.locator(`text="${newRoomName}"`)).toBeVisible({ timeout: 5000 });
    }
  });

  test('should handle private messages', async () => {
    await page1.goto('/chat');
    await page2.goto('/chat');
    
    // Look for users list
    const usersList = page1.locator('.users-list, [data-testid="online-users"]');
    
    if (await usersList.isVisible({ timeout: 2000 }).catch(() => false)) {
      // Find user 2
      const user2Item = usersList.locator(`text=/${testEmail2}|user.*2/i`);
      
      if (await user2Item.isVisible({ timeout: 2000 }).catch(() => false)) {
        await user2Item.click();
        
        // Should open DM
        const dmInput = page1.locator('[data-testid="message-input"]');
        await dmInput.fill('Private message test');
        await page1.locator('[data-testid="send-button"]').click();
        
        // User 2 should receive notification or message
        await expect(page2.locator('text="Private message test"')).toBeVisible({ timeout: 5000 });
      }
    }
  });

  test('should show online/offline status', async () => {
    await page1.goto('/chat');
    
    // Look for status indicators
    const statusIndicators = page1.locator('.status-indicator, .online-status, [data-status]');
    
    if (await statusIndicators.first().isVisible({ timeout: 2000 }).catch(() => false)) {
      // Should have online class or green color
      const firstIndicator = statusIndicators.first();
      const classes = await firstIndicator.getAttribute('class');
      const style = await firstIndicator.getAttribute('style');
      
      expect(classes || style).toMatch(/online|green|#0f0|rgb\(0,\s*255,\s*0\)/i);
    }
  });

  test('should handle message search', async () => {
    await page1.goto('/chat');
    
    // Send searchable message
    const searchableMessage = `Searchable ${Date.now()}`;
    await page1.fill('[data-testid="message-input"]', searchableMessage);
    await page1.locator('[data-testid="send-button"]').click();
    
    // Look for search
    const searchInput = page1.locator('input[placeholder*="Search"], [data-testid="search-messages"]');
    
    if (await searchInput.isVisible({ timeout: 2000 }).catch(() => false)) {
      await searchInput.fill('Searchable');
      await searchInput.press('Enter');
      
      // Should highlight or filter messages
      await expect(page1.locator(`text="${searchableMessage}"`)).toBeVisible();
    }
  });
});