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

/**
 * R9FE-102 Workflow Verification: Cannibalization bulk generate drafts
 *
 * Golden Path:
 *   1. Navigate to Cannibalization page
 *   2. Default filters (no status, no min_impact selected)
 *   3. Click "Select all N matching"
 *   4. Open ScopeCostModal
 *   5. Cost estimate loads
 *   6. "Generate Drafts" button is ENABLED (previously permanently disabled — the bug)
 *   7. POST to create batch with mode=filter succeeds
 *
 * Sad Paths:
 *   - Loading state: modal shows spinner while estimate loads
 *   - Error state: estimate POST fails → error message, button disabled
 *   - Empty state: no matching cases (edge case)
 *   - Concurrent requests: double-click Generate → debounced to single POST
 *   - Double-submit: rapid button clicks → only one POST
 *
 * Assertions:
 *   - Zero uncaught console errors
 *   - Zero failed XHR requests (4xx/5xx)
 *   - Golden path reaches success state: modal closes + redirects to batch-ai.show
 */

test.describe('R9FE-102: Cannibalization bulk generate drafts', () => {
  test.beforeEach(async ({ page }) => {
    // Navigate to Cannibalization index with a test site
    // The seeded user has at least one site with cannibalization data
    await page.goto('/cannibalization');

    // Wait for page to load and verify we're on the Cannibalization page
    await expect(page.locator('h1')).toContainText('Cannibalization', { timeout: 10000 });
  });

  test('Golden path: Generate Drafts button is enabled with default filters', async ({ page }) => {
    // Verify default filters are empty/undefined (no status, no min_impact selected)
    const statusFilter = page.locator('[data-testid="status-filter"]');
    const impactFilter = page.locator('[data-testid="min-impact-filter"]');

    // Both filters should show "Select..." or similar empty state
    await expect(statusFilter).toBeVisible();
    await expect(impactFilter).toBeVisible();

    // Click "Select all N matching" button (part of BulkActionBar)
    const selectAllBtn = page.locator('button:has-text("Select all")').first();
    await expect(selectAllBtn).toBeVisible();
    await selectAllBtn.click();

    // Verify "Select all" count is shown
    const selectionDisplay = page.locator('[data-testid="bulk-selection"]');
    await expect(selectionDisplay).toContainText(/\d+/);

    // Open ScopeCostModal (likely triggered by "Generate Drafts" or similar action)
    // Look for a button that opens the modal or rewrite action
    const openModalBtn = page.locator('button:has-text("Generate Drafts")').first();
    if (await openModalBtn.isVisible()) {
      await openModalBtn.click();
    } else {
      // Alternative: look for a bulk action that opens the modal
      const bulkActionBtn = page.locator('[data-testid="bulk-action-generate"]');
      if (await bulkActionBtn.isVisible()) {
        await bulkActionBtn.click();
      }
    }

    // Wait for modal to appear
    const modal = page.locator('[role="dialog"]').filter({ hasText: /cost estimate/i });
    await expect(modal).toBeVisible({ timeout: 10000 });

    // Wait for cost estimate to load (POST to estimate endpoint)
    const costDisplay = page.locator('text=Cost Estimate');
    await expect(costDisplay).toBeVisible({ timeout: 10000 });

    // KEY ASSERTION: "Generate Drafts" button inside the modal must be ENABLED
    // This is the bug fix — previously it was always disabled on Cannibalization
    const generateBtn = page.locator('[role="dialog"] button:has-text("Generate Drafts")');
    await expect(generateBtn).not.toBeDisabled();

    // Verify no console errors so far
    const consoleLogs = await page.evaluate(() => {
      return (window as unknown as { __consoleLogs?: { level: string }[] }).__consoleLogs || [];
    });
    const errorLogs = consoleLogs.filter((log: { level: string }) => log.level === 'error');
    expect(errorLogs.length).toBe(0);
  });

  test('Loading state: modal shows spinner while estimate loads', async ({ page }) => {
    // Delay the estimate POST to observe loading state
    await page.route('**/api/batch/estimate', (route) => {
      setTimeout(() => route.continue(), 1500);
    });

    // Select all and open modal
    const selectAllBtn = page.locator('button:has-text("Select all")').first();
    await expect(selectAllBtn).toBeVisible();
    await selectAllBtn.click();

    const openModalBtn = page.locator('button:has-text("Generate Drafts")').first();
    if (await openModalBtn.isVisible()) {
      await openModalBtn.click();
    }

    const modal = page.locator('[role="dialog"]').filter({ hasText: /cost estimate/i });
    await expect(modal).toBeVisible({ timeout: 10000 });

    // While loading, the button should be disabled
    const generateBtn = page.locator('[role="dialog"] button:has-text("Generate Drafts")');
    await expect(generateBtn).toBeDisabled();

    // After estimate loads, button should be enabled
    const costDisplay = page.locator('text=Cost Estimate');
    await expect(costDisplay).toBeVisible({ timeout: 15000 });
    await expect(generateBtn).not.toBeDisabled();
  });

  test('Error state: estimate POST fails → error message shown, button disabled', async ({ page }) => {
    // Abort the estimate POST to simulate network error
    await page.route('**/api/batch/estimate', (route) => {
      route.abort('failed');
    });

    const selectAllBtn = page.locator('button:has-text("Select all")').first();
    await expect(selectAllBtn).toBeVisible();
    await selectAllBtn.click();

    const openModalBtn = page.locator('button:has-text("Generate Drafts")').first();
    if (await openModalBtn.isVisible()) {
      await openModalBtn.click();
    }

    const modal = page.locator('[role="dialog"]').filter({ hasText: /cost estimate/i });
    await expect(modal).toBeVisible({ timeout: 10000 });

    // Wait for error message
    const errorMsg = page.locator('text=Failed to load estimate').or(page.locator('text=Error'));
    await expect(errorMsg).toBeVisible({ timeout: 10000 });

    // Generate button should remain disabled
    const generateBtn = page.locator('[role="dialog"] button:has-text("Generate Drafts")');
    await expect(generateBtn).toBeDisabled();
  });

  test('Double-submit protection: Generate button debounces rapid clicks', async ({ page }) => {
    let postCount = 0;
    await page.route('**/api/batch', (route) => {
      postCount++;
      route.continue();
    });

    // Select all and open modal
    const selectAllBtn = page.locator('button:has-text("Select all")').first();
    await expect(selectAllBtn).toBeVisible();
    await selectAllBtn.click();

    const openModalBtn = page.locator('button:has-text("Generate Drafts")').first();
    if (await openModalBtn.isVisible()) {
      await openModalBtn.click();
    }

    const modal = page.locator('[role="dialog"]').filter({ hasText: /cost estimate/i });
    await expect(modal).toBeVisible({ timeout: 10000 });

    // Wait for estimate to load
    const costDisplay = page.locator('text=Cost Estimate');
    await expect(costDisplay).toBeVisible({ timeout: 10000 });

    // Rapid clicks on Generate
    const generateBtn = page.locator('[role="dialog"] button:has-text("Generate Drafts")');
    await generateBtn.click();
    await generateBtn.click();
    await generateBtn.click();

    // Wait for response and redirects
    await page.waitForNavigation({ timeout: 10000 }).catch(() => {});

    // Should only have submitted once (or at most twice with a small debounce window)
    expect(postCount).toBeLessThanOrEqual(2);
  });

  test('Zero console errors on golden path', async ({ page }) => {
    // Capture all console messages
    const consoleLogs: { level: string; text: string }[] = [];
    page.on('console', (msg) => {
      consoleLogs.push({
        level: msg.type(),
        text: msg.text(),
      });
    });

    // Run golden path
    const selectAllBtn = page.locator('button:has-text("Select all")').first();
    await expect(selectAllBtn).toBeVisible();
    await selectAllBtn.click();

    const openModalBtn = page.locator('button:has-text("Generate Drafts")').first();
    if (await openModalBtn.isVisible()) {
      await openModalBtn.click();
    }

    const modal = page.locator('[role="dialog"]').filter({ hasText: /cost estimate/i });
    await expect(modal).toBeVisible({ timeout: 10000 });

    const costDisplay = page.locator('text=Cost Estimate');
    await expect(costDisplay).toBeVisible({ timeout: 10000 });

    const generateBtn = page.locator('[role="dialog"] button:has-text("Generate Drafts")');
    await expect(generateBtn).not.toBeDisabled();

    // Assert zero error logs
    const errorLogs = consoleLogs.filter((log) => log.level === 'error');
    expect(errorLogs).toHaveLength(0);
  });

  test('Zero failed XHR requests on golden path', async ({ page }) => {
    const failedRequests: string[] = [];
    page.on('response', (response) => {
      if (response.status() >= 400 && response.request().resourceType() === 'xhr') {
        failedRequests.push(`${response.status()} ${response.request().url()}`);
      }
    });

    // Run golden path
    const selectAllBtn = page.locator('button:has-text("Select all")').first();
    await expect(selectAllBtn).toBeVisible();
    await selectAllBtn.click();

    const openModalBtn = page.locator('button:has-text("Generate Drafts")').first();
    if (await openModalBtn.isVisible()) {
      await openModalBtn.click();
    }

    const modal = page.locator('[role="dialog"]').filter({ hasText: /cost estimate/i });
    await expect(modal).toBeVisible({ timeout: 10000 });

    const costDisplay = page.locator('text=Cost Estimate');
    await expect(costDisplay).toBeVisible({ timeout: 10000 });

    // Assert zero failed requests
    expect(failedRequests).toHaveLength(0);
  });
});
