import { test, expect, Page } from '@playwright/test';
import * as path from 'path';

// Test data
const testEmail = `user+files-${Date.now()}@lab.veza`;
const testPassword = `V3za!files-${Date.now()}`;

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

test.describe('File Management', () => {
  test.beforeEach(async ({ page }) => {
    await registerAndLogin(page);
  });

  test('should load files interface', async ({ page }) => {
    await page.goto('/files');
    
    // Check main elements
    await expect(page.locator('[data-testid="files-container"], .files-container, #files')).toBeVisible();
    await expect(page.locator('button:has-text("Upload"), [data-testid="upload-button"]')).toBeVisible();
    
    // Check for file list/grid
    const filesList = page.locator('[data-testid="files-list"], .files-list, .files-grid');
    await expect(filesList).toBeVisible();
  });

  test('should upload text file', async ({ page }) => {
    await page.goto('/files');
    
    // Create test file
    const fileName = `test-${Date.now()}.txt`;
    const fileContent = 'This is a test file content';
    
    // Find upload input
    const uploadInput = page.locator('input[type="file"]');
    
    if (!await uploadInput.isVisible()) {
      // Click upload button to reveal input
      await page.locator('button:has-text("Upload")').click();
    }
    
    // Upload file
    await uploadInput.setInputFiles({
      name: fileName,
      mimeType: 'text/plain',
      buffer: Buffer.from(fileContent),
    });
    
    // Wait for upload to complete
    await expect(page.locator(`text="${fileName}"`)).toBeVisible({ timeout: 10000 });
    
    // Check file details
    const fileItem = page.locator(`[data-filename="${fileName}"], text="${fileName}"`).locator('xpath=ancestor::*[contains(@class, "file")]');
    
    // Should show file size
    await expect(fileItem.locator('text=/\\d+\\s*(B|KB|MB)/i')).toBeVisible();
  });

  test('should upload image file', async ({ page }) => {
    await page.goto('/files');
    
    const imagePath = path.join(__dirname, '../../data/images/avatar.jpg');
    
    // Upload image
    const uploadInput = page.locator('input[type="file"]');
    await uploadInput.setInputFiles(imagePath);
    
    // Wait for upload
    await expect(page.locator('text=avatar.jpg')).toBeVisible({ timeout: 10000 });
    
    // Should show thumbnail
    const thumbnail = page.locator('img[src*="avatar"], [data-testid="file-thumbnail"]');
    if (await thumbnail.isVisible({ timeout: 2000 }).catch(() => false)) {
      const src = await thumbnail.getAttribute('src');
      expect(src).toBeTruthy();
    }
  });

  test('should handle multiple file upload', async ({ page }) => {
    await page.goto('/files');
    
    // Create multiple test files
    const files = [];
    for (let i = 0; i < 3; i++) {
      files.push({
        name: `multi-${i}-${Date.now()}.txt`,
        mimeType: 'text/plain',
        buffer: Buffer.from(`Content of file ${i}`),
      });
    }
    
    // Upload multiple files
    const uploadInput = page.locator('input[type="file"]');
    await uploadInput.setInputFiles(files);
    
    // All files should appear
    for (const file of files) {
      await expect(page.locator(`text="${file.name}"`)).toBeVisible({ timeout: 10000 });
    }
  });

  test('should show upload progress', async ({ page }) => {
    await page.goto('/files');
    
    // Create large file (1MB)
    const largeContent = 'x'.repeat(1024 * 1024);
    const fileName = `large-${Date.now()}.txt`;
    
    // Start upload
    const uploadInput = page.locator('input[type="file"]');
    await uploadInput.setInputFiles({
      name: fileName,
      mimeType: 'text/plain',
      buffer: Buffer.from(largeContent),
    });
    
    // Look for progress indicator
    const progressBar = page.locator('[role="progressbar"], .upload-progress, [data-testid="upload-progress"]');
    
    if (await progressBar.isVisible({ timeout: 1000 }).catch(() => false)) {
      // Progress should be visible during upload
      const progress = await progressBar.getAttribute('aria-valuenow') || 
                      await progressBar.getAttribute('value');
      expect(progress).toBeTruthy();
    }
  });

  test('should handle file size limits', async ({ page }) => {
    await page.goto('/files');
    
    // Try to upload file larger than limit (simulate)
    await page.evaluate(() => {
      // Trigger file size error
      const event = new CustomEvent('error', { 
        detail: { message: 'File too large' } 
      });
      window.dispatchEvent(event);
    });
    
    // Or try actual large file
    const veryLargeContent = 'x'.repeat(50 * 1024 * 1024); // 50MB
    const uploadInput = page.locator('input[type="file"]');
    
    try {
      await uploadInput.setInputFiles({
        name: 'too-large.txt',
        mimeType: 'text/plain',
        buffer: Buffer.from(veryLargeContent),
      });
      
      // Should show error
      await expect(page.locator('text=/too large|size limit|exceeds/i')).toBeVisible({ timeout: 5000 });
    } catch (e) {
      // File might be too large for Playwright itself
      console.log('Skipping very large file test');
    }
  });

  test('should preview text files', async ({ page }) => {
    await page.goto('/files');
    
    // Upload text file
    const fileName = `preview-${Date.now()}.txt`;
    const fileContent = 'Preview this text content\nLine 2\nLine 3';
    
    await page.locator('input[type="file"]').setInputFiles({
      name: fileName,
      mimeType: 'text/plain',
      buffer: Buffer.from(fileContent),
    });
    
    // Wait for file to appear
    await page.waitForTimeout(2000);
    
    // Click file to preview
    await page.locator(`text="${fileName}"`).click();
    
    // Should show preview
    const preview = page.locator('[data-testid="file-preview"], .file-preview, .modal');
    if (await preview.isVisible({ timeout: 2000 }).catch(() => false)) {
      await expect(preview.locator('text="Preview this text content"')).toBeVisible();
    }
  });

  test('should download files', async ({ page }) => {
    await page.goto('/files');
    
    // Upload a file first
    const fileName = `download-${Date.now()}.txt`;
    await page.locator('input[type="file"]').setInputFiles({
      name: fileName,
      mimeType: 'text/plain',
      buffer: Buffer.from('Download me'),
    });
    
    await page.waitForTimeout(2000);
    
    // Find download button
    const fileItem = page.locator(`text="${fileName}"`).locator('xpath=ancestor::*[contains(@class, "file")]');
    const downloadButton = fileItem.locator('button[aria-label="Download"], [data-testid="download-file"]');
    
    if (await downloadButton.isVisible({ timeout: 2000 }).catch(() => false)) {
      // Start download
      const downloadPromise = page.waitForEvent('download');
      await downloadButton.click();
      const download = await downloadPromise;
      
      // Verify download
      expect(download.suggestedFilename()).toBe(fileName);
    }
  });

  test('should delete files', async ({ page }) => {
    await page.goto('/files');
    
    // Upload a file
    const fileName = `delete-${Date.now()}.txt`;
    await page.locator('input[type="file"]').setInputFiles({
      name: fileName,
      mimeType: 'text/plain',
      buffer: Buffer.from('Delete me'),
    });
    
    await page.waitForTimeout(2000);
    
    // Find delete button
    const fileItem = page.locator(`text="${fileName}"`).locator('xpath=ancestor::*[contains(@class, "file")]');
    const deleteButton = fileItem.locator('button[aria-label="Delete"], [data-testid="delete-file"]');
    
    if (await deleteButton.isVisible({ timeout: 2000 }).catch(() => false)) {
      await deleteButton.click();
      
      // Confirm deletion if needed
      const confirmButton = page.locator('button:has-text("Confirm"), button:has-text("Delete")').last();
      if (await confirmButton.isVisible({ timeout: 1000 }).catch(() => false)) {
        await confirmButton.click();
      }
      
      // File should be removed
      await expect(page.locator(`text="${fileName}"`)).not.toBeVisible({ timeout: 5000 });
    }
  });

  test('should rename files', async ({ page }) => {
    await page.goto('/files');
    
    // Upload a file
    const fileName = `rename-${Date.now()}.txt`;
    await page.locator('input[type="file"]').setInputFiles({
      name: fileName,
      mimeType: 'text/plain',
      buffer: Buffer.from('Rename me'),
    });
    
    await page.waitForTimeout(2000);
    
    // Find rename option
    const fileItem = page.locator(`text="${fileName}"`).locator('xpath=ancestor::*[contains(@class, "file")]');
    
    // Right-click or find menu
    await fileItem.click({ button: 'right' });
    const renameOption = page.locator('text="Rename"');
    
    if (await renameOption.isVisible({ timeout: 1000 }).catch(() => false)) {
      await renameOption.click();
      
      // Enter new name
      const newName = `renamed-${Date.now()}.txt`;
      const input = page.locator('input[value*="rename"]');
      await input.fill(newName);
      await input.press('Enter');
      
      // New name should appear
      await expect(page.locator(`text="${newName}"`)).toBeVisible({ timeout: 5000 });
      await expect(page.locator(`text="${fileName}"`)).not.toBeVisible();
    }
  });

  test('should search files', async ({ page }) => {
    await page.goto('/files');
    
    // Upload files with different names
    const searchTerm = `searchable-${Date.now()}`;
    const files = [
      `${searchTerm}-1.txt`,
      `${searchTerm}-2.txt`,
      `other-file.txt`,
    ];
    
    for (const fileName of files) {
      await page.locator('input[type="file"]').setInputFiles({
        name: fileName,
        mimeType: 'text/plain',
        buffer: Buffer.from('Content'),
      });
      await page.waitForTimeout(500);
    }
    
    // Search
    const searchInput = page.locator('input[placeholder*="Search"], [data-testid="search-files"]');
    if (await searchInput.isVisible()) {
      await searchInput.fill(searchTerm);
      await searchInput.press('Enter');
      
      // Should show only matching files
      await expect(page.locator(`text="${searchTerm}-1.txt"`)).toBeVisible();
      await expect(page.locator(`text="${searchTerm}-2.txt"`)).toBeVisible();
      await expect(page.locator('text="other-file.txt"')).not.toBeVisible();
    }
  });

  test('should sort files', async ({ page }) => {
    await page.goto('/files');
    
    // Upload files with different dates/sizes
    const files = [
      { name: 'a-file.txt', content: 'Small' },
      { name: 'z-file.txt', content: 'Large content here' },
      { name: 'm-file.txt', content: 'Medium size' },
    ];
    
    for (const file of files) {
      await page.locator('input[type="file"]').setInputFiles({
        name: file.name,
        mimeType: 'text/plain',
        buffer: Buffer.from(file.content),
      });
      await page.waitForTimeout(500);
    }
    
    // Find sort dropdown
    const sortDropdown = page.locator('select[aria-label*="Sort"], [data-testid="sort-files"]');
    
    if (await sortDropdown.isVisible()) {
      // Sort by name
      await sortDropdown.selectOption('name');
      
      // Check order
      const fileNames = await page.locator('.file-name').allTextContents();
      expect(fileNames[0]).toContain('a-file');
      expect(fileNames[fileNames.length - 1]).toContain('z-file');
    }
  });

  test('should show file details', async ({ page }) => {
    await page.goto('/files');
    
    // Upload file
    const fileName = `details-${Date.now()}.txt`;
    const fileContent = 'File with details';
    
    await page.locator('input[type="file"]').setInputFiles({
      name: fileName,
      mimeType: 'text/plain',
      buffer: Buffer.from(fileContent),
    });
    
    await page.waitForTimeout(2000);
    
    // Click info button or file
    const fileItem = page.locator(`text="${fileName}"`).locator('xpath=ancestor::*[contains(@class, "file")]');
    const infoButton = fileItem.locator('button[aria-label="Info"], [data-testid="file-info"]');
    
    if (await infoButton.isVisible()) {
      await infoButton.click();
    } else {
      await fileItem.click();
    }
    
    // Should show details modal/panel
    const details = page.locator('[data-testid="file-details"], .file-details');
    if (await details.isVisible({ timeout: 2000 }).catch(() => false)) {
      await expect(details.locator(`text="${fileName}"`)).toBeVisible();
      await expect(details.locator('text=/size/i')).toBeVisible();
      await expect(details.locator('text=/type.*text/i')).toBeVisible();
      await expect(details.locator('text=/uploaded/i')).toBeVisible();
    }
  });

  test('should handle drag and drop upload', async ({ page }) => {
    await page.goto('/files');
    
    // Find drop zone
    const dropZone = page.locator('[data-testid="drop-zone"], .drop-zone, .files-container');
    
    // Create data transfer
    const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
    
    // Simulate drag over
    await dropZone.dispatchEvent('dragover', { dataTransfer });
    
    // Should show drop indicator
    await expect(dropZone).toHaveClass(/drag-over|dropping/);
    
    // Note: Full drag-drop file upload is complex in Playwright
    // This test mainly checks the UI responds to drag events
  });
});