/**
 * Cart Management Test
 * 
 * Tags: @commerce @p1 @ui
 * 
 * Tests cart management functionality including:
 * - Quantity updates in cart
 * - Remove individual items
 * - Bulk selection and deletion
 * - Cart filters
 * - Total recalculation
 * - Cart persistence
 */

import { test, expect } from '@playwright/test';
import { printTestCase, printSuccess, printWarning, waitForDataTable, clearCart, ensureAuthenticated } from '../../helpers/test-helpers';

// Helper function to add item to cart
async function addItemToCart(page: any, rowIndex: number = 0, quantity: number = 1): Promise<void> {
  const productsTable = page.locator('#productsTable');
  const row = productsTable.locator('tbody tr:visible').nth(rowIndex);
  
  // Find quantity input - wrapped in .quantity-control div
  const qtyInput = row.locator('.quantity-control input').first();
  await qtyInput.clear();
  await qtyInput.fill(quantity.toString());
  await page.waitForTimeout(500);  // Let the field update
  
  const addButton = row.locator('.add-to-cart-btn').first();
  await addButton.click({ force: true });  // Force click to bypass interceptors
  await page.waitForTimeout(3000);  // Increased wait for AJAX
  
  // Handle duplicate item dialog if it appears
  const confirmBtn = page.locator('.swal2-confirm');
  try {
    if (await confirmBtn.isVisible({ timeout: 5000 })) {
      await confirmBtn.click({ force: true });
      await page.waitForTimeout(2000);
    }
  } catch {
    // Dialog may not appear, continue
  }
}

// Helper function to get cart total
async function getCartTotal(page: any): Promise<number> {
  const totalElement = page.locator('#currentcartTotalPrice, [id*="cart-total"], .cart-total').first();
  if (await totalElement.isVisible().catch(() => false)) {
    const totalText = await totalElement.textContent() || '0';
    return parseFloat(totalText.replace(/[^0-9.]/g, ''));
  }
  return 0;
}

// Helper function to get cart item count (only visible data rows, not DataTables empty row)
async function getCartItemCount(page: any): Promise<number> {
  const count = await page.evaluate(() => {
    const rows = Array.from(document.querySelectorAll('#cartTable tbody tr'));
    
    // Filter out hidden rows and empty message rows
    const visibleRows = rows.filter(row => {
      const element = row as HTMLElement;
      // Check if row is actually visible (not display:none)
      if (element.style.display === 'none' || !element.offsetParent) {
        return false;
      }
      // Check if it's the empty message row
      if (element.classList.contains('dataTables_empty') || 
          element.textContent?.includes('No data available')) {
        return false;
      }
      return true;
    });
    
    return visibleRows.length;
  });
  
  return count;
}

// clearCart is now imported from test-helpers

test.describe('02_Core_Commerce - Cart Management', () => {
  // Use authenticated state for all tests in this suite
  test.use({ storageState: 'auth.json' });
  
  test.beforeEach(async ({ page }) => {
    // Ensure we're authenticated before navigating anywhere
    await ensureAuthenticated(page);
    
    await page.goto('/shop');
    await page.waitForLoadState('load');
    
    // Wait for products DataTable to initialize and load data
    await waitForDataTable(page, '#productsTable', 20000);
    
    // NOTE: Cart management tests add their own test data,
    // so afterEach cleanup is sufficient
  });
  
  test.afterEach(async ({ page }) => {
    // Cleanup: Clear cart after each test
    await clearCart(page);
  });
  
  test('Test Case 1: Verify cart table structure', async ({ page }) => {
    printTestCase(1, 'Verify Cart Table Structure');
    
    // Add an item first to ensure cart table is visible
    await addItemToCart(page, 0, 1);
    
    // Verify cart table exists
    const cartTable = page.locator('#cartTable');
    await expect(cartTable).toBeVisible({ timeout: 5000 });
    printSuccess('Cart table is visible');
    
    // Verify table headers
    const headers = cartTable.locator('thead th');
    const headerCount = await headers.count();
    expect(headerCount).toBeGreaterThan(0);
    printSuccess(`Found ${headerCount} cart table headers`);
    
    // Check for expected columns
    const headerTexts = await headers.allTextContents();
    const expectedColumns = ['product', 'price', 'quantity', 'total', 'action', 'delete', 'remove'];
    
    for (const expectedCol of expectedColumns) {
      const found = headerTexts.some(text => 
        text.toLowerCase().includes(expectedCol)
      );
      if (found) {
        printSuccess(`Column found: ${expectedCol}`);
        break; // Found at least one expected column
      }
    }
    
    // Verify cart has at least one row
    const cartRows = cartTable.locator('tbody tr');
    const rowCount = await cartRows.count();
    expect(rowCount).toBeGreaterThan(0);
    printSuccess(`Cart has ${rowCount} item(s)`);
  });
  
  test('Test Case 2: Test quantity update in cart', async ({ page }) => {
    printTestCase(2, 'Test Quantity Update in Cart');
    
    // Add item to cart
    await addItemToCart(page, 0, 2);
    
    const cartTable = page.locator('#cartTable');
    const cartRow = cartTable.locator('tbody tr').first();
    
    // Get initial total
    const initialTotal = await getCartTotal(page);
    printSuccess(`Initial cart total: ${initialTotal}`);
    
    // Find quantity input in cart
    const cartQtyInput = cartRow.locator('input[type="number"], input.quantity-input, input[name*="quantity"]').first();
    await expect(cartQtyInput).toBeVisible({ timeout: 5000 });
    
    const initialQty = await cartQtyInput.inputValue();
    printSuccess(`Initial quantity: ${initialQty}`);
    
    // Update quantity
    await cartQtyInput.clear();
    await cartQtyInput.fill('5');
    
    // Trigger update (may need to blur or click update button)
    const updateBtn = cartRow.locator('button:has-text("Update"), button.update-quantity');
    if (await updateBtn.isVisible().catch(() => false)) {
      await updateBtn.click();
      printSuccess('Update button clicked');
    } else {
      // Try triggering blur event
      await cartQtyInput.blur();
      printSuccess('Quantity input blurred to trigger update');
    }
    
    // Wait for cart total to actually change instead of arbitrary timeout
    await page.waitForFunction(
      (expectedInitial) => {
        const totalEl = document.querySelector('#currentcartTotalPrice, [id*="cart-total"], .cart-total');
        if (!totalEl) return false;
        const currentTotal = parseFloat(totalEl.textContent?.replace(/[^\d.-]/g, '') || '0');
        return currentTotal > expectedInitial;
      },
      initialTotal,
      { timeout: 10000 }
    ).catch(() => {
      // Fallback: just verify quantity changed
      console.warn('Could not verify total change, checking quantity instead');
    });
    
    // Verify quantity changed
    const updatedQty = await cartQtyInput.inputValue();
    expect(updatedQty).toBe('5');
    printSuccess(`Quantity updated to: ${updatedQty}`);
    
    // Verify total recalculated
    const updatedTotal = await getCartTotal(page);
    expect(updatedTotal).toBeGreaterThan(initialTotal);
    printSuccess(`Cart total updated to: ${updatedTotal}`);
  });
  
  test('Test Case 3: Test remove individual item', async ({ page }) => {
    printTestCase(3, 'Test Remove Individual Item');
    
    // Add multiple items
    await addItemToCart(page, 0, 1);
    await addItemToCart(page, 1, 1);
    
    const cartTable = page.locator('#cartTable');
    
    // Get initial cart count
    const initialCount = await cartTable.locator('tbody tr').count();
    printSuccess(`Initial cart count: ${initialCount}`);
    
    // Find remove button for first item
    const firstRow = cartTable.locator('tbody tr').first();
    const removeBtn = firstRow.locator('button:has-text("Remove"), button:has-text("Delete"), button.remove-item, button.delete-item, i.fa-trash').first();
    
    if (await removeBtn.isVisible().catch(() => false)) {
      await removeBtn.click();
      
      // Handle confirmation dialog if present
      const confirmBtn = page.locator('.swal2-confirm, button:has-text("Yes"), button:has-text("Confirm")');
      if (await confirmBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
        await confirmBtn.click();
        printSuccess('Confirmed deletion');
      }
      
      // Wait for cart count to actually decrease instead of arbitrary timeout
      await page.waitForFunction(
        (expectedInitial) => {
          const rows = document.querySelectorAll('#cartTable tbody tr');
          const visibleRows = Array.from(rows).filter(row => {
            const style = window.getComputedStyle(row);
            return style.display !== 'none' && !row.classList.contains('dataTables_empty');
          });
          return visibleRows.length < expectedInitial;
        },
        initialCount,
        { timeout: 10000 }
      ).catch(() => {
        // Fallback: just check count
        console.warn('Could not verify count decrease via waitForFunction');
      });
      
      // Verify item removed
      const updatedCount = await cartTable.locator('tbody tr:not(.dataTables_empty)').filter({ hasNotText: /no data/i }).count();
      expect(updatedCount).toBeLessThan(initialCount);
      printSuccess(`Item removed. Updated cart count: ${updatedCount}`);
    } else {
      printWarning('Remove button not found - may use different selector');
    }
  });
  
  test('Test Case 4: Test bulk selection', async ({ page }) => {
    printTestCase(4, 'Test Bulk Selection');
    
    // Add multiple items
    await addItemToCart(page, 0, 1);
    await addItemToCart(page, 1, 1);
    await addItemToCart(page, 2, 1);
    
    const cartTable = page.locator('#cartTable');
    
    // Find select all checkbox
    const selectAllCheckbox = page.locator('#selectAllCartItems, input[type="checkbox"][id*="select-all"], thead input[type="checkbox"]').first();
    await expect(selectAllCheckbox).toBeVisible({ timeout: 5000 });
    printSuccess('Select all checkbox found');
    
    // Check select all
    await selectAllCheckbox.check();
    await page.waitForTimeout(500);
    
    // Verify individual checkboxes are checked
    const itemCheckboxes = cartTable.locator('tbody tr input[type="checkbox"]');
    const checkboxCount = await itemCheckboxes.count();
    
    let checkedCount = 0;
    for (let i = 0; i < checkboxCount; i++) {
      const isChecked = await itemCheckboxes.nth(i).isChecked();
      if (isChecked) checkedCount++;
    }
    
    expect(checkedCount).toBe(checkboxCount);
    printSuccess(`All ${checkboxCount} item checkboxes are checked`);
    
    // Uncheck select all
    await selectAllCheckbox.uncheck();
    await page.waitForTimeout(500);
    
    // Verify individual checkboxes are unchecked
    checkedCount = 0;
    for (let i = 0; i < checkboxCount; i++) {
      const isChecked = await itemCheckboxes.nth(i).isChecked();
      if (isChecked) checkedCount++;
    }
    
    expect(checkedCount).toBe(0);
    printSuccess('All item checkboxes are unchecked');
  });
  
  test('Test Case 5: Test bulk delete', async ({ page }) => {
    printTestCase(5, 'Test Bulk Delete');
    
    // Add multiple items
    await addItemToCart(page, 0, 1);
    await addItemToCart(page, 1, 1);
    await addItemToCart(page, 2, 1);
    
    const cartTable = page.locator('#cartTable');
    const initialCount = await cartTable.locator('tbody tr').count();
    printSuccess(`Initial cart count: ${initialCount}`);
    
    // Select all items
    const selectAllCheckbox = page.locator('#selectAllCartItems, input[type="checkbox"][id*="select-all"]').first();
    await selectAllCheckbox.check();
    await page.waitForTimeout(500);
    printSuccess('All items selected');
    
    // Click bulk delete button
    const bulkDeleteBtn = page.locator('#bulkDeleteBtn, button:has-text("Delete Selected"), button:has-text("Delete All"), button.bulk-delete').first();
    await expect(bulkDeleteBtn).toBeVisible({ timeout: 5000 });
    await bulkDeleteBtn.click();
    await page.waitForTimeout(1000);
    printSuccess('Bulk delete button clicked');
    
    // Confirm deletion
    const confirmBtn = page.locator('.swal2-confirm, button:has-text("Yes"), button:has-text("Confirm")');
    if (await confirmBtn.isVisible().catch(() => false)) {
      await confirmBtn.click();
      await page.waitForTimeout(1000);
      printSuccess('Deletion confirmed');
    }
    
    // Verify all items deleted
    const finalCount = await getCartItemCount(page);
    expect(finalCount).toBe(0);
    printSuccess('All items deleted - cart is empty');
  });
  
  test('Test Case 6: Test cart total recalculation', async ({ page }) => {
    printTestCase(6, 'Test Cart Total Recalculation');
    
    // Add first item
    await addItemToCart(page, 0, 2);
    const totalAfterFirst = await getCartTotal(page);
    printSuccess(`Total after first item: ${totalAfterFirst}`);
    
    // Add second item
    await addItemToCart(page, 1, 3);
    const totalAfterSecond = await getCartTotal(page);
    expect(totalAfterSecond).toBeGreaterThan(totalAfterFirst);
    printSuccess(`Total after second item: ${totalAfterSecond}`);
    
    // Update quantity of first item
    const cartTable = page.locator('#cartTable');
    const firstRow = cartTable.locator('tbody tr').first();
    const qtyInput = firstRow.locator('input[type="number"], input.quantity-input').first();
    
    await qtyInput.clear();
    await qtyInput.fill('5');
    await page.waitForTimeout(500);
    
    // Trigger update
    const updateBtn = firstRow.locator('button:has-text("Update")');
    if (await updateBtn.isVisible().catch(() => false)) {
      await updateBtn.click();
    } else {
      await qtyInput.blur();
    }
    
    // Wait for AJAX to complete and cart total to update
    await page.waitForTimeout(2000);
    
    // Wait for cart total to change from the previous value
    await page.waitForFunction(
      (previousTotal) => {
        const totalElement = document.querySelector('#currentcartTotalPrice, [id*="cart-total"], .cart-total');
        if (!totalElement) return false;
        const currentTotal = parseFloat(totalElement.textContent?.replace(/[^0-9.]/g, '') || '0');
        return currentTotal !== previousTotal && currentTotal > 0;
      },
      totalAfterSecond,
      { timeout: 10000 }
    ).catch(() => {
      console.warn('Timeout waiting for cart total to update');
    });
    
    await page.waitForTimeout(1000);
    
    const totalAfterUpdate = await getCartTotal(page);
    expect(totalAfterUpdate).toBeGreaterThan(totalAfterSecond);
    printSuccess(`Total after quantity update: ${totalAfterUpdate}`);
    
    // Remove an item
    const removeBtn = firstRow.locator('button:has-text("Remove"), button:has-text("Delete"), i.fa-trash').first();
    if (await removeBtn.isVisible().catch(() => false)) {
      await removeBtn.click();
      await page.waitForTimeout(1000);
      
      const confirmBtn = page.locator('.swal2-confirm');
      if (await confirmBtn.isVisible().catch(() => false)) {
        await confirmBtn.click();
        await page.waitForTimeout(1000);
      }
      
      const totalAfterRemoval = await getCartTotal(page);
      expect(totalAfterRemoval).toBeLessThan(totalAfterUpdate);
      printSuccess(`Total after item removal: ${totalAfterRemoval}`);
    }
  });
  
  test('Test Case 7: Test cart filters (if available)', async ({ page }) => {
    printTestCase(7, 'Test Cart Filters');
    
    // Add multiple items
    await addItemToCart(page, 0, 1);
    await addItemToCart(page, 1, 1);
    await addItemToCart(page, 2, 1);
    
    // Look for filter controls
    const filterSelect = page.locator('select.cart-filter, [id*="cart-filter"]');
    const filterInput = page.locator('input.cart-filter, input[placeholder*="filter" i]');
    
    const hasFilterSelect = await filterSelect.isVisible().catch(() => false);
    const hasFilterInput = await filterInput.isVisible().catch(() => false);
    
    if (hasFilterSelect) {
      printSuccess('Cart filter dropdown found');
      const options = filterSelect.locator('option');
      const optionCount = await options.count();
      
      if (optionCount > 1) {
        await filterSelect.selectOption({ index: 1 });
        await page.waitForTimeout(1000);
        printSuccess('Filter option selected');
      }
    } else if (hasFilterInput) {
      printSuccess('Cart filter input found');
      await filterInput.fill('test');
      await page.waitForTimeout(1000);
      printSuccess('Filter text entered');
    }
    // Cart filter controls should exist - if not found, verify cart table is functional
  });
  
  test('Test Case 8: Test cart item validation', async ({ page }) => {
    printTestCase(8, 'Test Cart Item Validation');
    
    // Add item to cart
    await addItemToCart(page, 0, 1);
    
    const cartTable = page.locator('#cartTable');
    const cartRow = cartTable.locator('tbody tr').first();
    
    // Test invalid quantity (0 or negative)
    const qtyInput = cartRow.locator('input[type="number"], input.quantity-input').first();
    
    // Try setting quantity to 0
    await qtyInput.clear();
    await qtyInput.fill('0');
    await page.waitForTimeout(500);
    await qtyInput.blur();
    await page.waitForTimeout(1000);
    
    // Check if validation error appears or quantity reverts
    const currentQty = await qtyInput.inputValue();
    const qtyNum = parseInt(currentQty);
    
    if (qtyNum > 0) {
      printSuccess('Zero quantity rejected - quantity reverted or validated');
    } else {
      printWarning('Zero quantity accepted - validation may not be implemented');
    }
    
    // Try setting negative quantity
    await qtyInput.clear();
    await qtyInput.fill('-5');
    await page.waitForTimeout(500);
    await qtyInput.blur();
    await page.waitForTimeout(1000);
    
    const negQty = await qtyInput.inputValue();
    const negQtyNum = parseInt(negQty);
    
    if (negQtyNum > 0) {
      printSuccess('Negative quantity rejected');
    } else {
      printWarning('Negative quantity accepted - validation may not be implemented');
    }
  });
  
  test('Test Case 9: Test cart persistence', async ({ page }) => {
    printTestCase(9, 'Test Cart Persistence');
    
    // Add items to cart
    await addItemToCart(page, 0, 2);
    await addItemToCart(page, 1, 3);
    
    const cartTable = page.locator('#cartTable');
    const initialCount = await cartTable.locator('tbody tr').count();
    const initialTotal = await getCartTotal(page);
    
    printSuccess(`Initial state - Items: ${initialCount}, Total: ${initialTotal}`);
    
    // Navigate away and back
    await page.goto('/');
    await page.waitForTimeout(1000);
    await page.goto('/shop');
    await page.waitForTimeout(2000);
    
    // Check if cart persisted
    const persistedCount = await cartTable.locator('tbody tr').count();
    const persistedTotal = await getCartTotal(page);
    
    if (persistedCount === initialCount && Math.abs(persistedTotal - initialTotal) < 0.01) {
      printSuccess(`Cart persisted - Items: ${persistedCount}, Total: ${persistedTotal}`);
    } else {
      printWarning(`Cart may not persist - Items: ${persistedCount}, Total: ${persistedTotal}`);
    }
  });
  
  test('Test Case 10: Test empty cart state', async ({ page }) => {
    printTestCase(10, 'Test Empty Cart State');
    
    // Ensure cart is empty
    await clearCart(page);
    
    // Wait for cart to actually be empty instead of arbitrary timeout
    await page.waitForFunction(() => {
      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;
      });
      return visibleRows.length === 0;
    }, { timeout: 15000 }).catch(async () => {
      // If wait fails, check one more time
      const finalCount = await getCartItemCount(page);
      if (finalCount > 0) {
        throw new Error(`Cart still has ${finalCount} items after clearCart`);
      }
    });
    
    // Check for empty cart message
    const emptyMessage = page.locator('.empty-cart, .no-items, [class*="empty"]').filter({ hasText: /empty|no item/i });
    const hasEmptyMessage = await emptyMessage.isVisible().catch(() => false);
    
    if (hasEmptyMessage) {
      const messageText = await emptyMessage.textContent();
      printSuccess(`Empty cart message found: ${messageText}`);
    } else {
      printWarning('No empty cart message found');
    }
    
    // Verify cart table is empty (count only visible data rows, not DataTables empty row)
    const rowCount = await getCartItemCount(page);
    
    expect(rowCount).toBe(0);
    printSuccess('Cart table is empty');
    
    // Verify total is 0
    const total = await getCartTotal(page);
    expect(total).toBe(0);
    printSuccess('Cart total is 0');
  });
});

