import { test, expect, Page } from '@playwright/test';
import { loginToJamUI, createAndJoinSession } from '../utils/test-helpers';
import { APIInterceptor } from '../utils/api-interceptor';

/**
 * Recording Controls Test Suite
 *
 * Tests recording functionality including:
 * - Opening recording modal
 * - Name validation
 * - Starting recording flow
 * - Button state transitions (Record → Recording → Stopping → Record)
 * - Stopping recording
 */

/**
 * Helper function to mock jamClient recording methods
 */
async function mockJamClientRecording(page: Page) {
  await page.evaluate(() => {
    const mockMethods = {
      StartMediaRecording: async (...args: any[]) => {
        console.log('[MOCK] StartMediaRecording called', args);
        // Simulate successful recording start by calling the callback
        setTimeout(() => {
          if ((window as any).JK?.HandleRecordingStartResult) {
            (window as any).JK.HandleRecordingStartResult(args[0], { success: true, reason: '', detail: '' }, 'test-client-id');
          }
        }, 500);
        return true;
      },
      FrontStopRecording: async (...args: any[]) => {
        console.log('[MOCK] FrontStopRecording called', args);
        return true;
      },
      GetAudioRecordingPreference: async () => {
        console.log('[MOCK] GetAudioRecordingPreference called');
        return 2; // Mix and stems
      },
      SetAudioRecordingPreference: async (...args: any[]) => {
        console.log('[MOCK] SetAudioRecordingPreference called', args);
        return true;
      },
      getOpenVideoSources: async () => {
        console.log('[MOCK] getOpenVideoSources called');
        return {
          webcam1: true,
          webcam2: false,
          screen_capture: true,
          session_video: false,
          process_status: 'ok',
        };
      },
      IsOBSAvailable: async () => {
        console.log('[MOCK] IsOBSAvailable called');
        return false;
      },
      RegisterRecordingCallbacks: async (...args: any[]) => {
        console.log('[MOCK] RegisterRecordingCallbacks called', args);
        return true;
      },
      SetVURefreshRate: async (...args: any[]) => {
        console.log('[MOCK] SetVURefreshRate called', args);
        return true;
      },
      SessionRegisterCallback: async (...args: any[]) => {
        console.log('[MOCK] SessionRegisterCallback called', args);
        return true;
      },
      SessionSetAlertCallback: async (...args: any[]) => {
        console.log('[MOCK] SessionSetAlertCallback called', args);
        return true;
      },
      SessionSetConnectionStatusRefreshRate: async (...args: any[]) => {
        console.log('[MOCK] SessionSetConnectionStatusRefreshRate called', args);
        return true;
      },
      getClientParentChildRole: async () => {
        console.log('[MOCK] getClientParentChildRole called');
        return 0;
      },
      getParentClientId: async () => {
        console.log('[MOCK] getParentClientId called');
        return '';
      },
    };

    // Replace jamClient methods if it exists
    if ((window as any).jamClient) {
      Object.assign((window as any).jamClient, mockMethods);
      console.log('[MOCK] jamClient recording methods replaced');
    } else {
      (window as any).jamClient = mockMethods;
      console.log('[MOCK] jamClient created with recording methods');
    }
  });
}

/**
 * Helper to intercept recording API calls
 */
async function mockRecordingAPI(page: Page) {
  // Mock start recording API
  await page.route('**/api/recordings/start', async (route) => {
    console.log('[MOCK API] POST /api/recordings/start intercepted');
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({
        id: 'mock-recording-id-' + Date.now(),
        music_session_id: 'test-session-id',
        duration: null,
        is_done: false,
        owner: { id: 1, name: 'Test User' },
        recorded_tracks: [
          { client_id: 'test-client-id', track_id: 1 },
        ],
        created_at: new Date().toISOString(),
      }),
    });
  });

  // Mock stop recording API
  await page.route('**/api/recordings/*/stop', async (route) => {
    console.log('[MOCK API] POST /api/recordings/*/stop intercepted');
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({
        id: 'mock-recording-id',
        music_session_id: 'test-session-id',
        duration: 30,
        is_done: true,
        owner: { id: 1, name: 'Test User' },
        recorded_tracks: [
          { client_id: 'test-client-id', track_id: 1 },
        ],
      }),
    });
  });

  // Mock get recording API
  await page.route('**/api/recordings/*', async (route) => {
    if (route.request().method() === 'GET') {
      console.log('[MOCK API] GET /api/recordings/* intercepted');
      await route.fulfill({
        status: 200,
        contentType: 'application/json',
        body: JSON.stringify({
          id: 'mock-recording-id',
          music_session_id: 'test-session-id',
          owner: { id: 1, name: 'Test User' },
          recorded_tracks: [
            { client_id: 'test-client-id', track_id: 1 },
          ],
        }),
      });
    } else {
      await route.continue();
    }
  });
}

test.describe('Recording Controls', () => {
  let apiInterceptor: APIInterceptor;

  test.beforeEach(async ({ page }) => {
    // Increase timeout for these tests
    test.setTimeout(90000);

    // Set up API interceptor
    apiInterceptor = new APIInterceptor();
    await apiInterceptor.intercept(page);

    // Mock recording API endpoints
    await mockRecordingAPI(page);

    // Login and join a session
    await loginToJamUI(page);
    await createAndJoinSession(page);

    // Mock jamClient recording methods after session is created
    await mockJamClientRecording(page);
  });

  test('should display Record button in session toolbar', async ({ page }) => {
    // Wait for session to load
    await page.waitForTimeout(3000);

    // Find Record button
    const recordButton = page.locator('button:has-text("Record")');
    await expect(recordButton).toBeVisible({ timeout: 10000 });
  });

  test('should open recording modal when Record button is clicked', async ({ page }) => {
    await page.waitForTimeout(3000);

    // Click Record button
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();

    // Wait for modal to open
    await page.waitForTimeout(1000);

    // Verify modal title
    const modalTitle = page.locator('text=Make Recording');
    await expect(modalTitle).toBeVisible({ timeout: 5000 });

    // Verify Start Recording button is present
    const startButton = page.locator('button:has-text("Start Recording")');
    await expect(startButton).toBeVisible();
  });

  test('should show validation error when starting recording without name', async ({ page }) => {
    await page.waitForTimeout(3000);

    // Open recording modal
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);

    // Click Start Recording without entering a name
    const startButton = page.locator('button:has-text("Start Recording")');
    await startButton.click();

    // Wait for error message
    await page.waitForTimeout(500);

    // Verify error message is displayed
    const errorMessage = page.locator('text=Please enter a recording name');
    await expect(errorMessage).toBeVisible({ timeout: 5000 });
  });

  test('should close modal when Close button is clicked', async ({ page }) => {
    await page.waitForTimeout(3000);

    // Open recording modal
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);

    // Verify modal is open
    await expect(page.locator('text=Make Recording')).toBeVisible();

    // Click Close button
    const closeButton = page.locator('.modal-footer button:has-text("Close")');
    await closeButton.click();

    // Verify modal is closed
    await page.waitForTimeout(500);
    await expect(page.locator('text=Make Recording')).not.toBeVisible();
  });

  test('should have audio-only selected by default', async ({ page }) => {
    await page.waitForTimeout(3000);

    // Open recording modal
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);

    // Verify audio-only is checked
    const audioOnlyRadio = page.locator('input[value="audio-only"]');
    await expect(audioOnlyRadio).toBeChecked();
  });

  test('should allow selecting audio and video recording type', async ({ page }) => {
    await page.waitForTimeout(3000);

    // Open recording modal
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);

    // Click audio-video radio
    const audioVideoRadio = page.locator('input[value="audio-video"]');
    await audioVideoRadio.click();

    // Verify it's selected
    await expect(audioVideoRadio).toBeChecked();
  });

  test('should allow entering recording name', async ({ page }) => {
    await page.waitForTimeout(3000);

    // Open recording modal
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);

    // Enter recording name
    const nameInput = page.locator('input[placeholder="Recording Name"]');
    await nameInput.fill('My Test Recording');

    // Verify input value
    await expect(nameInput).toHaveValue('My Test Recording');
  });

  test('should allow toggling voice chat checkbox', async ({ page }) => {
    await page.waitForTimeout(3000);

    // Open recording modal
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);

    // Find voice chat checkbox
    const voiceChatCheckbox = page.locator('input[name="includeChat"]');

    // Should be unchecked by default
    await expect(voiceChatCheckbox).not.toBeChecked();

    // Click to check
    await voiceChatCheckbox.click();
    await expect(voiceChatCheckbox).toBeChecked();

    // Click to uncheck
    await voiceChatCheckbox.click();
    await expect(voiceChatCheckbox).not.toBeChecked();
  });

  test('should start recording when valid name is provided', async ({ page }) => {
    await page.waitForTimeout(3000);

    // Open recording modal
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);

    // Enter recording name
    const nameInput = page.locator('input[placeholder="Recording Name"]');
    await nameInput.fill('Test Recording');

    // Click Start Recording
    const startButton = page.locator('button:has-text("Start Recording")');
    await startButton.click();

    // Wait for recording to start (modal should close)
    await page.waitForTimeout(2000);

    // Modal should be closed
    await expect(page.locator('.modal-header:has-text("Make Recording")')).not.toBeVisible({ timeout: 5000 });

    // Record button should now show "Recording"
    // Note: This depends on the native client callback being triggered
    // In real tests, this would need proper callback simulation
  });

  test.skip('should show Recording button state when recording is active', async ({ page }) => {
    // This test requires full native client integration
    // Skipped for now - would need to properly simulate HandleRecordingStartResult callback

    await page.waitForTimeout(3000);

    // Start recording
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);

    const nameInput = page.locator('input[placeholder="Recording Name"]');
    await nameInput.fill('Test Recording');

    const startButton = page.locator('button:has-text("Start Recording")');
    await startButton.click();

    // Wait for state change
    await page.waitForTimeout(3000);

    // Button should show "Recording"
    const recordingButton = page.locator('button:has-text("Recording")');
    await expect(recordingButton).toBeVisible({ timeout: 10000 });
  });

  test.skip('should stop recording when Recording button is clicked', async ({ page }) => {
    // This test requires the recording to be in active state first
    // Skipped for now - would need full integration test setup

    // Assuming recording is active...
    const recordingButton = page.locator('button:has-text("Recording")');

    // Click to stop
    await recordingButton.click();

    // Should show "Stopping..." briefly
    const stoppingButton = page.locator('button:has-text("Stopping")');
    await expect(stoppingButton).toBeVisible({ timeout: 5000 });

    // Then should return to "Record"
    await page.waitForTimeout(3000);
    const recordButton = page.locator('button:has-text("Record")');
    await expect(recordButton).toBeVisible({ timeout: 10000 });
  });
});

test.describe('Recording Modal Form Controls', () => {
  test.beforeEach(async ({ page }) => {
    test.setTimeout(60000);

    // Simple setup - just go to modal
    const apiInterceptor = new APIInterceptor();
    await apiInterceptor.intercept(page);
    await mockRecordingAPI(page);

    await loginToJamUI(page);
    await createAndJoinSession(page);
    await mockJamClientRecording(page);

    // Open recording modal
    await page.waitForTimeout(3000);
    const recordButton = page.locator('button:has-text("Record")');
    await recordButton.click();
    await page.waitForTimeout(500);
  });

  test('should display all audio format options', async ({ page }) => {
    // Find audio format select
    const audioFormatSelect = page.locator('select').nth(0);

    // Check options
    await expect(audioFormatSelect.locator('option[value="wav"]')).toBeAttached();
    await expect(audioFormatSelect.locator('option[value="mp3"]')).toBeAttached();
    await expect(audioFormatSelect.locator('option[value="flac"]')).toBeAttached();
  });

  test('should display video format options', async ({ page }) => {
    // Find video format select (disabled by default for audio-only)
    const videoFormatSelect = page.locator('select').nth(1);

    // Check options
    await expect(videoFormatSelect.locator('option:has-text("MP4")')).toBeAttached();
    await expect(videoFormatSelect.locator('option:has-text("FLC")')).toBeAttached();
  });

  test('should disable video format when audio-only is selected', async ({ page }) => {
    // Verify audio-only is selected
    const audioOnlyRadio = page.locator('input[value="audio-only"]');
    await expect(audioOnlyRadio).toBeChecked();

    // Video format should be disabled
    const videoFormatSelect = page.locator('select').nth(1);
    await expect(videoFormatSelect).toBeDisabled();
  });

  test('should enable video format when audio-video is selected', async ({ page }) => {
    // Select audio-video
    const audioVideoRadio = page.locator('input[value="audio-video"]');
    await audioVideoRadio.click();

    // Video format should be enabled (though OBS check may show alert)
    // Note: OBS availability is mocked to return false, so an alert may appear
  });
});
