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

// Test data
const testEmail = `user+stream-${Date.now()}@lab.veza`;
const testPassword = `V3za!stream-${Date.now()}`;
const audioFile = path.join(__dirname, '../../data/audio/demo-track-10s.mp3');

// 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|stream)/, { timeout: 10000 });
}

test.describe('Streaming Functionality', () => {
  test.beforeEach(async ({ page }) => {
    // Register and login
    await registerAndLogin(page);
  });

  test('should load streaming interface', async ({ page }) => {
    await page.goto('/stream');
    
    // Check main streaming elements
    await expect(page.locator('[data-testid="stream-container"], .stream-container, #stream')).toBeVisible();
    
    // Check for player controls
    const player = page.locator('audio, video, [data-testid="media-player"]');
    await expect(player).toBeVisible();
    
    // Check for upload button
    await expect(page.locator('button:has-text("Upload"), [data-testid="upload-audio"]')).toBeVisible();
  });

  test('should upload audio file', async ({ page }) => {
    await page.goto('/stream');
    
    // Find upload button
    const uploadButton = page.locator('input[type="file"][accept*="audio"], [data-testid="audio-upload-input"]');
    
    if (!await uploadButton.isVisible()) {
      // Click button to reveal file input
      await page.locator('button:has-text("Upload")').click();
    }
    
    // Upload file
    await uploadButton.setInputFiles(audioFile);
    
    // Wait for upload to complete
    await expect(page.locator('text=/upload.*complete|success|uploaded/i')).toBeVisible({ timeout: 30000 });
    
    // File should appear in list or player
    await expect(page.locator('text=demo-track-10s.mp3')).toBeVisible();
  });

  test('should play uploaded audio', async ({ page }) => {
    await page.goto('/stream');
    
    // Upload a file first
    const uploadButton = page.locator('input[type="file"][accept*="audio"]');
    await uploadButton.setInputFiles(audioFile);
    await page.waitForTimeout(2000); // Wait for upload
    
    // Find play button
    const playButton = page.locator('button[aria-label="Play"], [data-testid="play-button"], .play-button');
    
    if (await playButton.isVisible()) {
      await playButton.click();
      
      // Check if audio is playing
      const isPlaying = await page.evaluate(() => {
        const audio = document.querySelector('audio') as HTMLAudioElement;
        return audio && !audio.paused;
      });
      
      expect(isPlaying).toBeTruthy();
      
      // Pause button should now be visible
      await expect(page.locator('button[aria-label="Pause"], [data-testid="pause-button"]')).toBeVisible();
    }
  });

  test('should show audio waveform or visualizer', async ({ page }) => {
    await page.goto('/stream');
    
    // Upload file
    const uploadButton = page.locator('input[type="file"][accept*="audio"]');
    await uploadButton.setInputFiles(audioFile);
    await page.waitForTimeout(2000);
    
    // Check for waveform/visualizer
    const visualizer = page.locator('canvas[class*="waveform"], canvas[class*="visualizer"], .audio-waveform, svg.waveform');
    
    if (await visualizer.isVisible({ timeout: 5000 }).catch(() => false)) {
      // Visualizer should be rendered
      const box = await visualizer.boundingBox();
      expect(box?.width).toBeGreaterThan(0);
      expect(box?.height).toBeGreaterThan(0);
    }
  });

  test('should handle volume control', async ({ page }) => {
    await page.goto('/stream');
    
    // Find volume control
    const volumeSlider = page.locator('input[type="range"][aria-label*="Volume"], [data-testid="volume-slider"]');
    
    if (await volumeSlider.isVisible()) {
      // Get initial volume
      const initialVolume = await volumeSlider.inputValue();
      
      // Change volume
      await volumeSlider.fill('50');
      
      // Verify volume changed
      const audio = page.locator('audio');
      const audioVolume = await audio.evaluate((el: HTMLAudioElement) => el.volume * 100);
      expect(audioVolume).toBeCloseTo(50, 1);
    }
  });

  test('should show playback progress', async ({ page }) => {
    await page.goto('/stream');
    
    // Upload and play file
    const uploadButton = page.locator('input[type="file"][accept*="audio"]');
    await uploadButton.setInputFiles(audioFile);
    await page.waitForTimeout(2000);
    
    // Play audio
    await page.locator('button[aria-label="Play"], [data-testid="play-button"]').click();
    
    // Check progress bar
    const progressBar = page.locator('input[type="range"][aria-label*="Seek"], [data-testid="progress-bar"], .progress-bar');
    
    if (await progressBar.isVisible()) {
      // Wait a bit for playback
      await page.waitForTimeout(2000);
      
      // Progress should have moved
      const progress = await progressBar.inputValue();
      expect(parseInt(progress)).toBeGreaterThan(0);
    }
    
    // Check time display
    const timeDisplay = page.locator('.current-time, [data-testid="current-time"]');
    if (await timeDisplay.isVisible()) {
      const time = await timeDisplay.textContent();
      expect(time).not.toBe('0:00');
    }
  });

  test('should handle seek functionality', async ({ page }) => {
    await page.goto('/stream');
    
    // Upload and play file
    const uploadButton = page.locator('input[type="file"][accept*="audio"]');
    await uploadButton.setInputFiles(audioFile);
    await page.waitForTimeout(2000);
    
    // Find seek bar
    const seekBar = page.locator('input[type="range"][aria-label*="Seek"], [data-testid="seek-bar"]');
    
    if (await seekBar.isVisible()) {
      // Seek to middle
      await seekBar.fill('50');
      
      // Verify audio currentTime changed
      const audio = page.locator('audio');
      const currentTime = await audio.evaluate((el: HTMLAudioElement) => el.currentTime);
      const duration = await audio.evaluate((el: HTMLAudioElement) => el.duration);
      
      expect(currentTime).toBeCloseTo(duration * 0.5, 1);
    }
  });

  test('should show playlist or track list', async ({ page }) => {
    await page.goto('/stream');
    
    // Check for playlist
    const playlist = page.locator('[data-testid="playlist"], .playlist, .track-list');
    
    if (await playlist.isVisible()) {
      // Upload multiple files
      for (let i = 0; i < 3; i++) {
        const uploadButton = page.locator('input[type="file"][accept*="audio"]');
        await uploadButton.setInputFiles(audioFile);
        await page.waitForTimeout(1000);
      }
      
      // Should show multiple tracks
      const tracks = await playlist.locator('.track-item, [data-testid^="track-"]').count();
      expect(tracks).toBeGreaterThanOrEqual(3);
    }
  });

  test('should handle playback controls', async ({ page }) => {
    await page.goto('/stream');
    
    // Upload file
    const uploadButton = page.locator('input[type="file"][accept*="audio"]');
    await uploadButton.setInputFiles(audioFile);
    await page.waitForTimeout(2000);
    
    // Test play/pause
    const playButton = page.locator('button[aria-label="Play"]');
    await playButton.click();
    
    const pauseButton = page.locator('button[aria-label="Pause"]');
    await expect(pauseButton).toBeVisible();
    await pauseButton.click();
    
    await expect(playButton).toBeVisible();
    
    // Test skip controls if available
    const nextButton = page.locator('button[aria-label="Next"], [data-testid="next-track"]');
    const prevButton = page.locator('button[aria-label="Previous"], [data-testid="prev-track"]');
    
    if (await nextButton.isVisible()) {
      await nextButton.click();
      // Should move to next track or end
    }
    
    if (await prevButton.isVisible()) {
      await prevButton.click();
      // Should move to previous track or beginning
    }
  });

  test('should handle repeat and shuffle', async ({ page }) => {
    await page.goto('/stream');
    
    // Check for repeat button
    const repeatButton = page.locator('button[aria-label*="Repeat"], [data-testid="repeat-button"]');
    
    if (await repeatButton.isVisible()) {
      await repeatButton.click();
      
      // Should show active state
      await expect(repeatButton).toHaveClass(/active|on/);
    }
    
    // Check for shuffle button
    const shuffleButton = page.locator('button[aria-label*="Shuffle"], [data-testid="shuffle-button"]');
    
    if (await shuffleButton.isVisible()) {
      await shuffleButton.click();
      
      // Should show active state
      await expect(shuffleButton).toHaveClass(/active|on/);
    }
  });

  test('should show metadata for playing track', async ({ page }) => {
    await page.goto('/stream');
    
    // Upload file
    const uploadButton = page.locator('input[type="file"][accept*="audio"]');
    await uploadButton.setInputFiles(audioFile);
    await page.waitForTimeout(2000);
    
    // Check for metadata display
    await expect(page.locator('text=demo-track-10s')).toBeVisible();
    
    // Check for duration
    const duration = page.locator('.duration, [data-testid="track-duration"]');
    if (await duration.isVisible()) {
      const durationText = await duration.textContent();
      expect(durationText).toMatch(/\d+:\d+/);
    }
  });

  test('should handle streaming errors gracefully', async ({ page }) => {
    await page.goto('/stream');
    
    // Try to play non-existent track
    await page.evaluate(() => {
      const audio = document.querySelector('audio') as HTMLAudioElement;
      if (audio) {
        audio.src = 'https://invalid-url/non-existent.mp3';
        audio.play().catch(() => {});
      }
    });
    
    // Should show error message
    await expect(page.locator('text=/error|failed|cannot.*play/i')).toBeVisible({ timeout: 5000 });
  });

  test('should support keyboard controls', async ({ page }) => {
    await page.goto('/stream');
    
    // Upload file
    const uploadButton = page.locator('input[type="file"][accept*="audio"]');
    await uploadButton.setInputFiles(audioFile);
    await page.waitForTimeout(2000);
    
    // Focus player
    await page.locator('[data-testid="media-player"], audio').focus();
    
    // Test spacebar for play/pause
    await page.keyboard.press('Space');
    
    // Check if playing
    const isPlaying = await page.evaluate(() => {
      const audio = document.querySelector('audio') as HTMLAudioElement;
      return audio && !audio.paused;
    });
    
    expect(isPlaying).toBeTruthy();
    
    // Test arrow keys for seek
    await page.keyboard.press('ArrowRight');
    await page.waitForTimeout(500);
    
    const currentTime = await page.evaluate(() => {
      const audio = document.querySelector('audio') as HTMLAudioElement;
      return audio?.currentTime || 0;
    });
    
    expect(currentTime).toBeGreaterThan(0);
  });

  test('should remember volume preference', async ({ page }) => {
    await page.goto('/stream');
    
    // Set volume
    const volumeSlider = page.locator('input[type="range"][aria-label*="Volume"]');
    if (await volumeSlider.isVisible()) {
      await volumeSlider.fill('30');
      
      // Reload page
      await page.reload();
      
      // Volume should be remembered
      const savedVolume = await volumeSlider.inputValue();
      expect(parseInt(savedVolume)).toBe(30);
    }
  });
});