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

/**
 * Waitlist Feature E2E Tests
 *
 * Tests the complete waitlist functionality:
 * - Creating waitlists
 * - Viewing waitlists
 * - Adding customers to waitlists
 * - Editing waitlists
 * - Deleting waitlists
 * - Removing customers from waitlists
 */

// Increase timeout for all tests in this file
test.setTimeout(120000);

const TEST_EMAIL = 'guqo@mailinator.com';
const BASE_URL = process.env.BASE_URL || 'http://localhost:9000';
const STORAGE_STATE_PATH = path.join(__dirname, '.auth', 'waitlist-user.json');

/**
 * Helper function to login via OTP and save storage state
 * Uses retry logic for reliability
 */
async function loginAndSaveState(page: Page, context: BrowserContext): Promise<void> {
  for (let attempt = 1; attempt <= 3; attempt++) {
    try {
      console.log(`Login attempt ${attempt}...`);

      await page.goto(`${BASE_URL}/en/login`);
      await page.waitForLoadState('domcontentloaded');
      await page.waitForTimeout(2000);

      // Check page for errors and refresh if needed
      const hasError = await page.locator('text=Please refresh').isVisible({ timeout: 1000 }).catch(() => false) ||
                       await page.locator('text=Too many requests').isVisible({ timeout: 1000 }).catch(() => false);

      if (hasError) {
        console.log('Error detected, refreshing...');
        await page.waitForTimeout(3000);
        await page.reload();
        await page.waitForLoadState('domcontentloaded');
        await page.waitForTimeout(2000);
      }

      // Fill email and click send OTP
      const emailInput = page.locator('input[type="text"]').first();
      await expect(emailInput).toBeVisible({ timeout: 10000 });
      await emailInput.fill(TEST_EMAIL);
      await page.waitForTimeout(300);

      const sendButton = page.locator('button:has-text("Send OTP")').first();
      await expect(sendButton).toBeVisible();

      // Click and capture response
      const [response] = await Promise.all([
        page.waitForResponse(
          resp => resp.url().includes('/api/auth/login') && resp.request().method() === 'POST',
          { timeout: 15000 }
        ),
        sendButton.click()
      ]);

      const responseData = await response.json();

      if (response.status() !== 200 || !responseData.success) {
        throw new Error(`OTP request failed: ${JSON.stringify(responseData)}`);
      }

      // Fill OTP and verify
      const otpInput = page.locator('input[maxlength="6"]');
      await expect(otpInput).toBeVisible({ timeout: 10000 });
      await otpInput.fill(responseData.code);
      await page.waitForTimeout(300);

      const verifyButton = page.locator('button:has-text("Verify")').first();
      await expect(verifyButton).toBeEnabled({ timeout: 5000 });
      await verifyButton.click();

      // Wait for dashboard
      await page.waitForURL('**/dashboard**', { timeout: 30000 });

      // Save state
      const authDir = path.dirname(STORAGE_STATE_PATH);
      if (!fs.existsSync(authDir)) {
        fs.mkdirSync(authDir, { recursive: true });
      }
      await context.storageState({ path: STORAGE_STATE_PATH });

      console.log('Login successful!');
      return;

    } catch (error) {
      console.log(`Attempt ${attempt} failed:`, error);
      if (attempt === 3) throw error;
      await page.waitForTimeout(5000);
    }
  }
}

/**
 * Check if storage state exists and is recent (within 10 minutes)
 */
function hasValidStorageState(): boolean {
  if (!fs.existsSync(STORAGE_STATE_PATH)) return false;
  const stats = fs.statSync(STORAGE_STATE_PATH);
  const ageMs = Date.now() - stats.mtimeMs;
  return ageMs < 10 * 60 * 1000; // 10 minutes
}

/**
 * Helper function to ensure logged in
 */
async function ensureLoggedIn(page: Page, context: BrowserContext): Promise<void> {
  // Check if we already have valid auth stored
  if (hasValidStorageState()) {
    // Load the storage state (cookies)
    const storageState = JSON.parse(fs.readFileSync(STORAGE_STATE_PATH, 'utf-8'));
    if (storageState.cookies && storageState.cookies.length > 0) {
      await context.addCookies(storageState.cookies);
    }

    // Navigate to dashboard - cookies should be set
    await page.goto(`${BASE_URL}/en/dashboard`, { timeout: 60000 });
    await page.waitForLoadState('domcontentloaded', { timeout: 30000 });

    // Verify we're logged in by checking for dashboard content
    const welcomeText = page.getByText(/Welcome back/i);
    if (await welcomeText.isVisible({ timeout: 15000 }).catch(() => false)) {
      return;
    }
  }

  // Need to login
  await loginAndSaveState(page, context);
}

/**
 * Helper to navigate to waitlists tab
 */
async function navigateToWaitlists(page: Page): Promise<void> {
  // Click waitlists in sidebar
  await page.getByRole('button', { name: 'Waitlists' }).click();

  // Wait for waitlists panel content to load by checking for heading
  await expect(page.getByRole('heading', { name: 'Waitlists', level: 2 })).toBeVisible({ timeout: 60000 });
}

/**
 * Helper to navigate to My Waitlists tab
 */
async function navigateToMyWaitlists(page: Page): Promise<void> {
  await page.getByRole('button', { name: 'My Waitlists' }).click();
  await page.waitForTimeout(300);
}

/**
 * Helper to create a waitlist
 */
async function createWaitlist(
  page: Page,
  title: string,
  description: string = '',
  category: string = 'General'
): Promise<void> {
  // Click Create Waitlist button
  await page.getByRole('button', { name: 'Create Waitlist' }).first().click();
  await page.waitForTimeout(300);

  // Fill form
  const titleInput = page.getByRole('textbox').nth(1);
  await titleInput.fill(title);

  if (description) {
    const descInput = page.getByRole('textbox').nth(3);
    await descInput.fill(description);
  }

  if (category !== 'General') {
    await page.getByRole('combobox').selectOption(category);
  }

  // Submit
  await page.locator('form').getByRole('button', { name: 'Create Waitlist' }).click();

  // Wait for success - API can be slow, especially with dual database writes
  await expect(page.getByText('Waitlist created successfully!').first()).toBeVisible({ timeout: 30000 });
}

/**
 * Helper to add a customer to a waitlist
 */
async function addCustomerToWaitlist(
  page: Page,
  name: string,
  email: string,
  mobile: string,
  notes: string = ''
): Promise<void> {
  // Click Add User
  await page.getByRole('button', { name: 'Add User' }).click();
  await page.waitForTimeout(300);

  // Fill form
  await page.locator('form input[type="text"]').fill(name);
  await page.locator('input[type="email"]').fill(email);
  await page.getByRole('textbox', { name: '+974 5555' }).fill(mobile);

  if (notes) {
    await page.locator('textarea').fill(notes);
  }

  // Submit
  await page.locator('form').getByRole('button', { name: 'Add User' }).click();

  // Wait for success - API can be slow, especially with dual database writes
  await expect(page.getByText('User added successfully!').first()).toBeVisible({ timeout: 30000 });
}

// Generate unique identifiers for test data
const timestamp = Date.now();
const testWaitlistTitle = `Test Waitlist ${timestamp}`;
const testCustomerEmail = `testcustomer${timestamp}@example.com`;

test.describe('Waitlist Feature', () => {
  // Run tests serially to avoid rate limiting and share login state
  test.describe.configure({ mode: 'serial' });

  test.beforeEach(async ({ page, context }) => {
    // Login before each test (reuses session when possible)
    await ensureLoggedIn(page, context);
  });

  test('should navigate to waitlists section', async ({ page }) => {
    await navigateToWaitlists(page);

    // Verify we're on the waitlists page
    await expect(page.getByRole('heading', { name: 'Waitlists' })).toBeVisible();

    // Verify tabs exist
    await expect(page.getByRole('button', { name: 'Browse' })).toBeVisible();
    await expect(page.getByRole('button', { name: 'My Waitlists' })).toBeVisible();
  });

  test('should create a new waitlist', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Create waitlist
    await createWaitlist(
      page,
      testWaitlistTitle,
      'Test description for automated testing',
      'Service'
    );

    // Verify waitlist appears in the list
    await page.waitForTimeout(2000); // Wait for modal to close
    await expect(page.getByRole('heading', { name: testWaitlistTitle })).toBeVisible();
  });

  test('should display waitlist details correctly', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Check for the created waitlist or create a new one
    const waitlistExists = await page.getByRole('heading', { name: testWaitlistTitle }).isVisible().catch(() => false);

    if (!waitlistExists) {
      await createWaitlist(page, testWaitlistTitle, 'Test description', 'Service');
      await page.waitForTimeout(2000);
    }

    // Verify waitlist card elements
    const waitlistCard = page.locator(`text=${testWaitlistTitle}`).first();
    await expect(waitlistCard).toBeVisible();

    // Verify category badge
    await expect(page.getByText('Service').first()).toBeVisible();

    // Verify Active status
    await expect(page.getByText('Active').first()).toBeVisible();

    // Verify action buttons exist
    await expect(page.getByRole('button', { name: 'View Signups' }).first()).toBeVisible();
    await expect(page.getByRole('button', { name: 'Edit' }).first()).toBeVisible();
    await expect(page.getByRole('button', { name: 'Delete' }).first()).toBeVisible();
  });

  test('should add a customer to waitlist', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Ensure waitlist exists
    const waitlistExists = await page.getByRole('heading', { name: testWaitlistTitle }).isVisible().catch(() => false);

    if (!waitlistExists) {
      await createWaitlist(page, testWaitlistTitle, 'Test description', 'Service');
      await page.waitForTimeout(2000);
    }

    // Click View Signups
    await page.getByRole('button', { name: 'View Signups' }).first().click();
    await page.waitForTimeout(500);

    // Add customer
    await addCustomerToWaitlist(
      page,
      'Test Customer',
      testCustomerEmail,
      '+974 5555 9999',
      'Added via automated test'
    );

    // Verify customer appears in the table
    await page.waitForTimeout(2000);
    await expect(page.getByText('Test Customer')).toBeVisible();
    await expect(page.getByText(testCustomerEmail)).toBeVisible();
  });

  test('should show signups count after adding customer', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Check that a waitlist shows signup count
    const signupCountText = page.locator('text=/\\d+ signed up/').first();
    await expect(signupCountText).toBeVisible({ timeout: 5000 });
  });

  test('should edit a waitlist', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Ensure waitlist exists
    const waitlistExists = await page.getByRole('heading', { name: testWaitlistTitle }).isVisible().catch(() => false);

    if (!waitlistExists) {
      await createWaitlist(page, testWaitlistTitle, 'Test description', 'Service');
      await page.waitForTimeout(2000);
    }

    // Click Edit button
    await page.getByRole('button', { name: 'Edit' }).first().click();
    await page.waitForTimeout(500);

    // Verify edit modal opens
    await expect(page.getByRole('heading', { name: 'Edit' })).toBeVisible();

    // Update description
    const descInput = page.getByRole('textbox').nth(3);
    await descInput.fill('Updated description via automated test');

    // Save
    await page.getByRole('button', { name: 'Save' }).click();

    // Verify success message
    await expect(page.getByText('Waitlist updated successfully!').first()).toBeVisible({ timeout: 5000 });
  });

  test('should remove a customer from waitlist', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Navigate to a waitlist with signups
    const viewSignupsButton = page.getByRole('button', { name: 'View Signups' }).first();

    if (await viewSignupsButton.isVisible()) {
      await viewSignupsButton.click();
      await page.waitForTimeout(500);

      // Check if there are any signups to delete
      const deleteButton = page.getByRole('button', { name: 'Delete' }).first();

      if (await deleteButton.isVisible()) {
        // Get initial count
        const signupsHeader = page.locator('text=/Signups \\(\\d+\\)/');
        const headerText = await signupsHeader.textContent();
        const initialCount = parseInt(headerText?.match(/\d+/)?.[0] || '0');

        // Click delete on first signup
        await deleteButton.click();
        await page.waitForTimeout(1000);

        // Verify success message
        await expect(page.getByText('User removed successfully!').first()).toBeVisible({ timeout: 5000 });

        // If there were signups, verify count decreased
        if (initialCount > 1) {
          const newHeaderText = await signupsHeader.textContent();
          const newCount = parseInt(newHeaderText?.match(/\d+/)?.[0] || '0');
          expect(newCount).toBe(initialCount - 1);
        }
      }
    }
  });

  test('should prevent duplicate customer signups', async ({ page }) => {
    const uniqueEmail = `duplicate${Date.now()}@example.com`;

    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Ensure waitlist exists and navigate to signups
    const waitlistExists = await page.getByRole('heading', { name: testWaitlistTitle }).isVisible().catch(() => false);

    if (!waitlistExists) {
      await createWaitlist(page, testWaitlistTitle, 'Test description', 'Service');
      await page.waitForTimeout(2000);
    }

    // Navigate to signups
    await page.getByRole('button', { name: 'View Signups' }).first().click();
    await page.waitForTimeout(500);

    // Add first customer
    await addCustomerToWaitlist(page, 'First Customer', uniqueEmail, '+974 5555 1111');
    await page.waitForTimeout(2000);

    // Try to add same customer again
    await page.getByRole('button', { name: 'Add User' }).click();
    await page.waitForTimeout(300);

    await page.locator('form input[type="text"]').fill('Duplicate Customer');
    await page.locator('input[type="email"]').fill(uniqueEmail);
    await page.getByRole('textbox', { name: '+974 5555' }).fill('+974 5555 2222');
    await page.locator('form').getByRole('button', { name: 'Add User' }).click();

    // Verify error message about duplicate
    await expect(page.getByText(/already signed up|already exists/i).first()).toBeVisible({ timeout: 5000 });
  });

  test('should validate required fields when creating waitlist', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Open create modal
    await page.getByRole('button', { name: 'Create Waitlist' }).first().click();
    await page.waitForTimeout(300);

    // Try to submit without title
    await page.locator('form').getByRole('button', { name: 'Create Waitlist' }).click();

    // The form should not submit (HTML5 validation) or show error
    // Check that we're still on the modal
    await expect(page.getByRole('heading', { name: 'Create Waitlist' })).toBeVisible();
  });

  test('should validate required fields when adding customer', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Ensure waitlist exists
    const waitlistExists = await page.getByRole('heading', { name: testWaitlistTitle }).isVisible().catch(() => false);

    if (!waitlistExists) {
      await createWaitlist(page, testWaitlistTitle, 'Test description', 'Service');
      await page.waitForTimeout(2000);
    }

    // Navigate to signups
    await page.getByRole('button', { name: 'View Signups' }).first().click();
    await page.waitForTimeout(500);

    // Open add user modal
    await page.getByRole('button', { name: 'Add User' }).click();
    await page.waitForTimeout(300);

    // Try to submit without filling required fields
    await page.locator('form').getByRole('button', { name: 'Add User' }).click();

    // The form should not submit (HTML5 validation)
    await expect(page.getByRole('heading', { name: 'Add User' })).toBeVisible();
  });

  test('should delete a waitlist', async ({ page }) => {
    const deleteTestTitle = `Delete Test ${Date.now()}`;

    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Create a waitlist specifically for deletion
    await createWaitlist(page, deleteTestTitle, 'To be deleted', 'General');
    await page.waitForTimeout(3000); // Wait for modal to close and list to refresh

    // Verify it was created
    await expect(page.getByRole('heading', { name: deleteTestTitle })).toBeVisible({ timeout: 10000 });

    // Find the waitlist card and click its delete button
    // Get all delete buttons and find the one near our waitlist title
    const waitlistHeading = page.getByRole('heading', { name: deleteTestTitle });
    const waitlistCard = waitlistHeading.locator('xpath=ancestor::div[contains(@class, "bg-white")]');
    await waitlistCard.getByRole('button', { name: 'Delete' }).click();

    // Confirm deletion in modal
    await expect(page.getByRole('heading', { name: 'Confirm Delete' })).toBeVisible({ timeout: 10000 });
    await page.getByRole('button', { name: 'Delete' }).last().click();

    // Verify success message
    await expect(page.getByText('Waitlist deleted successfully!').first()).toBeVisible({ timeout: 10000 });

    // Verify waitlist is no longer visible
    await page.waitForTimeout(1000);
    await expect(page.getByRole('heading', { name: deleteTestTitle })).not.toBeVisible();
  });

  test('should navigate back from signups view', async ({ page }) => {
    await navigateToWaitlists(page);
    await navigateToMyWaitlists(page);

    // Ensure waitlist exists
    const waitlistExists = await page.getByRole('heading', { name: testWaitlistTitle }).isVisible().catch(() => false);

    if (!waitlistExists) {
      await createWaitlist(page, testWaitlistTitle, 'Test description', 'Service');
      await page.waitForTimeout(2000);
    }

    // Navigate to signups
    await page.getByRole('button', { name: 'View Signups' }).first().click();
    await page.waitForTimeout(500);

    // Verify we're in signups view
    await expect(page.getByText('Signups')).toBeVisible();

    // Click back button
    const backButton = page.locator('button').filter({ has: page.locator('img') }).first();
    await backButton.click();

    // Verify we're back to My Waitlists
    await expect(page.getByRole('button', { name: 'My Waitlists' })).toBeVisible();
  });
});

test.describe('Waitlist Browse Tab', () => {
  // Run tests serially to avoid rate limiting
  test.describe.configure({ mode: 'serial' });

  test.beforeEach(async ({ page, context }) => {
    await ensureLoggedIn(page, context);
  });

  test('should display browse tab with public waitlists', async ({ page }) => {
    await navigateToWaitlists(page);

    // Should be on Browse tab by default
    await expect(page.getByRole('button', { name: 'Browse' })).toBeVisible();

    // Verify subtitle
    await expect(page.getByText('Sign up to be first to know about new features and services')).toBeVisible();
  });

  test('should switch between Browse and My Waitlists tabs', async ({ page }) => {
    await navigateToWaitlists(page);

    // Click My Waitlists
    await page.getByRole('button', { name: 'My Waitlists' }).click();
    await expect(page.getByText('Create and manage your own waitlists')).toBeVisible();

    // Click Browse
    await page.getByRole('button', { name: 'Browse' }).click();
    await expect(page.getByText('Sign up to be first to know about new features and services')).toBeVisible();
  });
});
