/**
 * Checkout Flow Test
 * 
 * Tags: @commerce @p1 @smoke @checkout
 * 
 * Tests the complete checkout process:
 * - Place order immediately
 * - Schedule order for later
 * - Order confirmation
 * - Cart clearing after checkout
 * - Checkout validation
 */

import { test, expect } from '@playwright/test';
import { 
  printTestCase, 
  printSuccess, 
  printWarning, 
  waitForDataTable, 
  clearCart, 
  ensureAuthenticated,
  switchToBranchStore
} from '../../helpers/test-helpers';

// Helper to add items to cart
async function addItemsToCart(page: any, itemCount: number = 2): Promise<void> {
  await page.goto('/shop');
  await page.waitForLoadState('networkidle');
  await waitForDataTable(page, '#productsTable', 20000);
  
  for (let i = 0; i < itemCount; i++) {
    const row = page.locator('#productsTable tbody tr:visible').nth(i);
    const qtyInput = row.locator('.quantity-control input').first();
    await qtyInput.clear();
    await qtyInput.fill('1');
    
    const addButton = row.locator('.add-to-cart-btn').first();
    await addButton.click({ force: true });
    
    // Wait for add to cart AJAX to complete by checking for cart update
    await page.waitForFunction(() => {
      const cartTable = document.querySelector('#cartTable tbody');
      return cartTable && cartTable.children.length > 0;
    }, { timeout: 10000 });
    
    // Handle duplicate modal if it appears
    const confirmBtn = page.locator('.swal2-confirm');
    if (await confirmBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
      await confirmBtn.click({ force: true });
      await page.waitForLoadState('networkidle');
    }
  }
  
  printSuccess(`Added ${itemCount} items to cart`);
}

// Helper to get cart item count
async function getCartItemCount(page: any): Promise<number> {
  const count = await page.evaluate(() => {
    const rows = Array.from(document.querySelectorAll('#cartTable tbody tr'));
    const visibleRows = rows.filter(row => {
      const element = row as HTMLElement;
      if (element.style.display === 'none' || !element.offsetParent) {
        return false;
      }
      if (element.classList.contains('dataTables_empty') || 
          element.textContent?.includes('No data available')) {
        return false;
      }
      return true;
    });
    return visibleRows.length;
  });
  return count;
}

test.describe('02_Core_Commerce - Checkout', () => {
  test.use({ storageState: 'auth.json' });
  
  test.beforeEach(async ({ page }) => {
    await ensureAuthenticated(page);
    
    // Switch to branch store (required for placing regular orders)
    const isBranchStore = await switchToBranchStore(page);
    if (!isBranchStore) {
      console.log('⚠ Warning: Could not switch to branch store. Tests may fail.');
    }
  });
  
  test.afterEach(async ({ page }) => {
    // Cleanup: Clear cart after each test
    await clearCart(page);
  });
  
  test('Test Case 1: Place order immediately', async ({ page }) => {
    printTestCase(1, 'Place Order Immediately');
    
    // Add items to cart
    await addItemsToCart(page, 2);
    
    // Get cart count before checkout
    const cartCountBefore = await getCartItemCount(page);
    expect(cartCountBefore).toBeGreaterThan(0);
    printSuccess(`Cart has ${cartCountBefore} items`);
    
    // Wait for place order button to be ready and click it
    const placeOrderBtn = page.locator('button.place-order-btn');
    await expect(placeOrderBtn).toBeVisible({ timeout: 5000 });
    await placeOrderBtn.click({ force: true });
    
    // Wait for modal to open - Bootstrap 5 modal shows with .show class
    const orderModal = page.locator('#orderModal');
    // Wait for modal to be visible (Bootstrap 5 adds .show class and makes it visible)
    await expect(orderModal).toBeVisible({ timeout: 10000 });
    // Also wait for the show class to be added (Bootstrap 5 indicator)
    await page.waitForSelector('#orderModal.show', { timeout: 5000 }).catch(() => {});
    printSuccess('Order modal opened');
    
    // Wait for "Place Order Now" to be auto-selected (happens via setTimeout in the JS - 100ms delay)
    const placeNowRadio = page.locator('#placeOrderNow');
    await expect(placeNowRadio).toBeChecked({ timeout: 5000 });
    printSuccess('"Place Order Now" is selected by default');
    
    // Wait for submit button to be enabled
    const submitBtn = page.locator('#submitOrderBtn');
    await expect(submitBtn).toBeEnabled({ timeout: 5000 });
    
    // Click submit button
    await submitBtn.click();
    
    // Wait for success message or modal to close - check for SweetAlert success or modal hidden
    try {
      // Wait for success modal/alert to appear
      const successModal = page.locator('.swal2-success, .swal2-popup:has-text("success"), .alert-success');
      await successModal.waitFor({ state: 'visible', timeout: 10000 }).catch(() => {});
      printSuccess('Success message appeared');
      
      // Wait for order modal to close (Bootstrap 5 removes .show class)
      await expect(orderModal).not.toBeVisible({ timeout: 10000 });
      printSuccess('Order modal closed');
    } catch {
      // Fallback: just wait for modal to be hidden
      await expect(orderModal).not.toBeVisible({ timeout: 15000 });
      printSuccess('Order placed - modal closed');
    }
    
    // Wait for loadCartData() to complete - wait for cart to actually be cleared or reloaded
    // After successful order, loadCartData() is called which refreshes the cart table
    await page.waitForFunction(
      (expectedBefore) => {
        const table = document.querySelector('#cartTable');
        if (!table) return false;
        
        // Check if DataTable is done loading (not in processing state)
        const isProcessing = table.classList.contains('processing') || 
                            (table as HTMLElement).querySelector('.dataTables_processing');
        if (isProcessing) return false;
        
        const rows = document.querySelectorAll('#cartTable tbody tr');
        const visibleRows = Array.from(rows).filter(row => {
          const style = window.getComputedStyle(row);
          const element = row as HTMLElement;
          const isHidden = style.display === 'none' || !element.offsetParent;
          const isEmptyMsg = row.classList.contains('dataTables_empty') || 
                            row.textContent?.includes('No data available');
          return !isHidden && !isEmptyMsg;
        });
        // Cart should be empty (0) or reduced from before after order is placed
        return visibleRows.length < expectedBefore;
      },
      cartCountBefore,
      { timeout: 20000 }
    ).catch(async () => {
      // Fallback: wait a bit more and check count
      await page.waitForTimeout(2000);
      const fallbackCount = await getCartItemCount(page);
      if (fallbackCount >= cartCountBefore) {
        console.warn(`Cart may not have cleared - current count: ${fallbackCount}, before: ${cartCountBefore}`);
      }
    });
    
    // Verify cart is cleared or reduced
    const cartCountAfter = await getCartItemCount(page);
    if (cartCountAfter < cartCountBefore) {
      printSuccess(`Cart count after order: ${cartCountAfter} (was ${cartCountBefore})`);
    } else {
      printWarning(`Cart count unchanged: ${cartCountAfter} (was ${cartCountBefore})`);
    }
  });
  
  test('Test Case 2: Schedule order for later', async ({ page }) => {
    printTestCase(2, 'Schedule Order for Later');
    
    // Add items to cart
    await addItemsToCart(page, 1);
    
    // Click Place Orders button
    const placeOrderBtn = page.locator('button.place-order-btn');
    await placeOrderBtn.click({ force: true });
    
    // Wait for modal to open
    const orderModal = page.locator('#orderModal');
    await expect(orderModal).toBeVisible({ timeout: 5000 });
    printSuccess('Order modal opened');
    
    // Select "Schedule for Later" option
    const scheduleLaterRadio = page.locator('#scheduleOrderLater');
    await scheduleLaterRadio.click();
    printSuccess('Selected "Schedule for Later"');
    
    // Verify date input is visible (shown when schedule later is selected)
    const scheduleDateContainer = page.locator('#scheduleDateContainer');
    await expect(scheduleDateContainer).toBeVisible({ timeout: 2000 });
    printSuccess('Schedule date input is visible');
    
    // Enter future date
    const scheduledDateInput = page.locator('#scheduledDate');
    const futureDate = new Date();
    futureDate.setDate(futureDate.getDate() + 7); // 7 days from now
    const dateString = futureDate.toISOString().split('T')[0];
    await scheduledDateInput.fill(dateString);
    printSuccess(`Scheduled date set to: ${dateString}`);
    
    // Wait for submit button to be enabled (becomes enabled when date is selected)
    const submitBtn = page.locator('#submitOrderBtn');
    await expect(submitBtn).toBeEnabled({ timeout: 2000 });
    
    // Submit order
    await submitBtn.click();
    
    // Wait for the AJAX call to complete and modal to close
    await expect(orderModal).toBeHidden({ timeout: 10000 });
    printSuccess('Scheduled order placed successfully');
  });
  
  test('Test Case 3: Validate empty cart checkout', async ({ page }) => {
    printTestCase(3, 'Validate Empty Cart Checkout');
    
    await page.goto('/shop');
    await page.waitForLoadState('load');
    
    // Ensure cart is empty
    await clearCart(page);
    await page.waitForTimeout(1000);
    
    const cartCount = await getCartItemCount(page);
    expect(cartCount).toBe(0);
    printSuccess('Cart is empty');
    
    // Try to click Place Orders button
    const placeOrderBtn = page.locator('button.place-order-btn');
    
    // Check if button is disabled or clicking shows error
    const isDisabled = await placeOrderBtn.isDisabled().catch(() => false);
    
    if (isDisabled) {
      printSuccess('Place Orders button is disabled for empty cart');
    } else {
      // Button might be enabled, but should show error
      await placeOrderBtn.click();
      await page.waitForTimeout(1000);
      
      // Check for error message
      const errorAlert = page.locator('.swal2-popup.swal2-error, .alert-danger, .swal2-popup:has-text("error"), .swal2-popup:has-text("empty")');
      const hasError = await errorAlert.isVisible().catch(() => false);
      
      if (hasError) {
        printSuccess('Error message shown for empty cart');
      } else {
        printWarning('Empty cart validation behavior unclear');
      }
    }
  });
  
  test('Test Case 4: Verify modal content', async ({ page }) => {
    printTestCase(4, 'Verify Order Modal Content');
    
    // Add items to cart
    await addItemsToCart(page, 1);
    
    // Open order modal
    const placeOrderBtn = page.locator('button.place-order-btn');
    await placeOrderBtn.click();
    
    // Wait for modal to actually appear instead of arbitrary timeout
    const orderModal = page.locator('#orderModal');
    await expect(orderModal).toBeVisible({ timeout: 10000 });
    printSuccess('Order modal opened');
    
    // Verify modal has expected elements
    const modalTitle = orderModal.locator('.modal-title, h5, h6').first();
    const modalTitleText = await modalTitle.textContent();
    printSuccess(`Modal title: ${modalTitleText}`);
    
    // Verify place now option
    const placeNowRadio = page.locator('#placeOrderNow');
    await expect(placeNowRadio).toBeVisible();
    printSuccess('"Place Order Now" option found');
    
    // Verify schedule later option
    const scheduleLaterRadio = page.locator('#scheduleOrderLater');
    await expect(scheduleLaterRadio).toBeVisible();
    printSuccess('"Schedule for Later" option found');
    
    // Verify submit button
    const submitBtn = page.locator('#submitOrderBtn');
    await expect(submitBtn).toBeVisible();
    printSuccess('Submit button found');
    
    // Close modal
    const closeBtn = orderModal.locator('.btn-close, button:has-text("Close")').first();
    if (await closeBtn.isVisible().catch(() => false)) {
      await closeBtn.click();
      // Wait for modal to actually close instead of arbitrary timeout
      await expect(orderModal).not.toBeVisible({ timeout: 5000 }).catch(() => {});
      printSuccess('Modal closed');
    } else {
      await page.keyboard.press('Escape');
      // Wait for modal to actually close
      await expect(orderModal).not.toBeVisible({ timeout: 5000 }).catch(() => {});
      printSuccess('Modal closed with Escape');
    }
  });
  
  test('Test Case 5: Test scheduled date validation', async ({ page }) => {
    printTestCase(5, 'Test Scheduled Date Validation');
    
    // Add items to cart
    await addItemsToCart(page, 1);
    
    // Open order modal
    const placeOrderBtn = page.locator('button.place-order-btn');
    await placeOrderBtn.click({ force: true });
    
    // Wait for modal to be visible
    const orderModal = page.locator('#orderModal');
    await expect(orderModal).toBeVisible({ timeout: 5000 });
    
    // Select schedule later without entering date
    const scheduleLaterRadio = page.locator('#scheduleOrderLater');
    await scheduleLaterRadio.click();
    
    // Wait for date container to be visible
    const scheduleDateContainer = page.locator('#scheduleDateContainer');
    await expect(scheduleDateContainer).toBeVisible({ timeout: 2000 });
    
    // Check that submit button is disabled when no date is selected
    const submitBtn = page.locator('#submitOrderBtn');
    await expect(submitBtn).toBeDisabled({ timeout: 2000 });
    printSuccess('Date validation working - submit button is disabled without date');
  });
  
  test('Test Case 6: Test bulk order (selected items)', async ({ page }) => {
    printTestCase(6, 'Test Bulk Order with Selected Items');
    
    await page.goto('/shop');
    await page.waitForLoadState('load');
    await waitForDataTable(page, '#productsTable', 20000);
    
    // Add multiple items
    await addItemsToCart(page, 3);
    
    // Select specific items using checkboxes (if available)
    const cartTable = page.locator('#cartTable');
    const checkboxes = cartTable.locator('tbody tr input[type="checkbox"]');
    const checkboxCount = await checkboxes.count();
    
    if (checkboxCount > 0) {
      // Select first two items
      await checkboxes.nth(0).check();
      await checkboxes.nth(1).check();
      printSuccess('Selected 2 items for bulk order');
      
      // Look for bulk order button
      const bulkOrderBtn = page.locator('button:has-text("Place Selected"), button.bulk-order');
      if (await bulkOrderBtn.isVisible().catch(() => false)) {
        await bulkOrderBtn.click();
        printSuccess('Bulk order button clicked');
        
        // Order modal should open - wait for it instead of arbitrary timeout
        const orderModal = page.locator('#orderModal');
        await expect(orderModal).toBeVisible({ timeout: 10000 });
        printSuccess('Order modal opened for bulk order');
      } else {
        printWarning('Bulk order button not found - may not be implemented');
      }
    } else {
      printWarning('No checkboxes found in cart - bulk order may not be available');
    }
  });
  
  test('Test Case 7: Verify cart state after order', async ({ page }) => {
    printTestCase(7, 'Verify Cart State After Placing Order');
    
    // Add items to cart
    await addItemsToCart(page, 2);
    
    const cartCountBefore = await getCartItemCount(page);
    printSuccess(`Cart count before: ${cartCountBefore}`);
    
    // Place order
    const placeOrderBtn = page.locator('button.place-order-btn');
    await placeOrderBtn.click();
    
    // Wait for order modal to appear
    const orderModal = page.locator('#orderModal');
    await expect(orderModal).toBeVisible({ timeout: 10000 });
    
    const submitBtn = page.locator('#submitOrderBtn');
    await submitBtn.click();
    
    // Wait for success modal to appear instead of arbitrary timeout
    const okButton = page.locator('.swal2-confirm, button:has-text("OK")');
    await okButton.waitFor({ state: 'visible', timeout: 15000 }).catch(() => {});
    
    // Close any success modal
    if (await okButton.isVisible().catch(() => false)) {
      await okButton.click();
      // Wait for success modal to close
      await okButton.waitFor({ state: 'hidden', timeout: 5000 }).catch(() => {});
    }
    
    // Wait for cart to actually be cleared instead of arbitrary timeout
    await page.waitForFunction(
      (expectedBefore) => {
        const rows = document.querySelectorAll('#cartTable tbody tr');
        const visibleRows = Array.from(rows).filter(row => {
          const style = window.getComputedStyle(row);
          const element = row as HTMLElement;
          const isHidden = style.display === 'none' || !element.offsetParent;
          const isEmptyMsg = row.classList.contains('dataTables_empty') || 
                            row.textContent?.includes('No data available');
          return !isHidden && !isEmptyMsg;
        });
        // Cart should be empty (0) or reduced from before
        return visibleRows.length < expectedBefore;
      },
      cartCountBefore,
      { timeout: 15000 }
    ).catch(() => {
      // Fallback: just check count
      console.warn('Could not verify cart cleared via waitForFunction');
    });
    
    const cartCountAfter = await getCartItemCount(page);
    
    if (cartCountAfter === 0) {
      printSuccess('Cart cleared after order - all items removed');
    } else if (cartCountAfter < cartCountBefore) {
      printSuccess(`Cart reduced from ${cartCountBefore} to ${cartCountAfter} items`);
    } else {
      printWarning('Cart state unclear after order');
    }
  });
});

