/**
 * Add to Cart Test - Comprehensive
 * 
 * Tags: @commerce @p1 @smoke @ui
 * 
 * Mirrors Katalon's Add_To_Cart test with all verification:
 * - Initial setup and validation
 * - Product search and selection
 * - Quantity controls
 * - Add to cart functionality
 * - Cart state management
 * - Total calculations
 * - Duplicate item handling
 * - Data accuracy verification
 * - Business rules validation
 */

import { test, expect } from '@playwright/test';
import { printTestCase, printSuccess, printWarning, waitForDataTable, handleIncreaseQuantityModal, clearCart, ensureAuthenticated } from '../../helpers/test-helpers';

// Helper function to get cart item count
async function getCartItemCount(page: any): Promise<number> {
  // Use JavaScript to count only truly visible rows (not display:none)
  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;
}

test.describe('02_Core_Commerce - Add to Cart', () => {
  // 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);
    
    // CRITICAL: Clear cart BEFORE each test to ensure clean state
    await clearCart(page);
    
    // Verify cart is actually empty
    const cartCount = await getCartItemCount(page);
    if (cartCount > 0) {
      console.warn(`⚠️ Cart still has ${cartCount} items after clearCart, trying again...`);
      await clearCart(page);
    }
  });
  
  test.afterEach(async ({ page }) => {
    // CLEANUP: Also clear cart after each test
    await clearCart(page);
  });
  
  test('Test Case 1: Initial setup and validation', async ({ page }) => {
    printTestCase(1, 'Initial Setup and Validation');
    
    // Verify shop page loaded
    const currentUrl = page.url();
    expect(currentUrl).toContain('/shop');
    printSuccess('Shop page loaded successfully');
    
    // Verify products table present
    const productsTable = page.locator('#productsTable');
    await expect(productsTable).toBeVisible({ timeout: 10000 });
    printSuccess('Products table is visible');
    
    // Verify cart table present
    const cartTable = page.locator('#cartTable');
    const cartVisible = await cartTable.isVisible().catch(() => false);
    if (cartVisible) {
      printSuccess('Cart table is visible');
    } else {
      printWarning('Cart table not immediately visible - may appear after adding items');
    }
    
    // Verify page is fully loaded
    const readyState = await page.evaluate(() => document.readyState);
    expect(readyState).toBe('complete');
    printSuccess('Page is fully loaded');
  });
  
  test('Test Case 2: Test product search functionality', async ({ page }) => {
    printTestCase(2, 'Test Product Search Functionality');
    
    // Find CORRECT search input - #productsSearch
    const searchInput = page.locator('#productsSearch');
    await expect(searchInput).toBeVisible({ timeout: 5000 });
    printSuccess('Products search input found');
    
    // Get initial product count
    const productsTable = page.locator('#productsTable');
    await page.waitForTimeout(1500); // Wait for DataTable to load
    const initialRows = productsTable.locator('tbody tr');
    const initialCount = await initialRows.count();
    printSuccess(`Initial product count: ${initialCount}`);
    
    // Search for a product
    const searchTerm = 'wine';
    await searchInput.fill(searchTerm);
    await page.waitForTimeout(1500); // Wait for DataTable to filter
    
    const filteredRows = productsTable.locator('tbody tr:visible');
    const filteredCount = await filteredRows.count();
    printSuccess(`Filtered product count: ${filteredCount}`);
    
    // Clear search
    await searchInput.clear();
    await page.waitForTimeout(1500);
    printSuccess('Search cleared');
  });
  
  test('Test Case 3: Test product table structure', async ({ page }) => {
    printTestCase(3, 'Test Product Table Structure');
    
    const productsTable = page.locator('#productsTable');
    
    // Verify table headers
    const headers = productsTable.locator('thead th');
    const headerCount = await headers.count();
    expect(headerCount).toBeGreaterThan(0);
    printSuccess(`Found ${headerCount} table headers`);
    
    // Verify data rows (only count visible rows)
    const dataRows = productsTable.locator('tbody tr:visible');
    const rowCount = await dataRows.count();
    expect(rowCount).toBeGreaterThan(0);
    printSuccess(`Found ${rowCount} product rows`);
    
    // Verify first visible row has required elements
    const firstRow = dataRows.first();
    const rowText = await firstRow.textContent();
    expect(rowText).toBeTruthy();
    printSuccess('First row contains data');
  });
  
  test('Test Case 4: Test quantity controls', async ({ page }) => {
    printTestCase(4, 'Test Quantity Controls');
    
    const productsTable = page.locator('#productsTable');
    const firstRow = productsTable.locator('tbody tr:visible').first();
    
    // Find quantity input - it's wrapped in .quantity-control div
    const qtyInput = firstRow.locator('.quantity-control input').first();
    await expect(qtyInput).toBeVisible({ timeout: 5000 });
    printSuccess('Quantity input found');
    
    // Test direct input
    await qtyInput.clear();
    await qtyInput.fill('5');
    await page.waitForTimeout(500);
    const value = await qtyInput.inputValue();
    expect(value).toBe('5');
    printSuccess('Quantity input accepts direct values');
    
    // Test quantity up button (if available)
    const upBtn = firstRow.locator('button.quantity-up, button:has-text("+"), button[aria-label*="increase"]');
    if (await upBtn.isVisible().catch(() => false)) {
      await qtyInput.fill('2');
      const beforeQty = await qtyInput.inputValue();
      await upBtn.click();
      await page.waitForTimeout(500);
      const afterQty = await qtyInput.inputValue();
      if (parseInt(afterQty) > parseInt(beforeQty)) {
        printSuccess('Quantity up button increases value');
      }
    } else {
      printWarning('Quantity up button not found');
    }
    
    // Test quantity down button (if available)
    const downBtn = firstRow.locator('button.quantity-down, button:has-text("-"), button[aria-label*="decrease"]');
    if (await downBtn.isVisible().catch(() => false)) {
      await qtyInput.fill('5');
      const beforeQty = await qtyInput.inputValue();
      await downBtn.click();
      await page.waitForTimeout(500);
      const afterQty = await qtyInput.inputValue();
      if (parseInt(afterQty) < parseInt(beforeQty)) {
        printSuccess('Quantity down button decreases value');
      }
    } else {
      printWarning('Quantity down button not found');
    }
    
    // Reset quantity to 1
    await qtyInput.clear();
    await qtyInput.fill('1');
    printSuccess('Quantity reset to 1');
  });
  
  test('Test Case 5: Test add to cart functionality', async ({ page }) => {
    printTestCase(5, 'Test Add to Cart Functionality');
    
    const productsTable = page.locator('#productsTable');
    const firstRow = productsTable.locator('tbody tr:visible').first();
    
    // Get product details before adding
    const productName = await firstRow.locator('td').first().textContent();
    printSuccess(`Selected product: ${productName}`);
    
    // Set quantity - updated selector to match correct input
    const qtyInput = firstRow.locator('.quantity-control input').first();
    await qtyInput.clear();
    await qtyInput.fill('2');
    await page.waitForTimeout(500);
    
    const quantity = await qtyInput.inputValue();
    printSuccess(`Quantity set to: ${quantity}`);
    
    // Get cart count before adding
    const cartCountBefore = await getCartItemCount(page);
    printSuccess(`Cart items before: ${cartCountBefore}`);
    
    // Find and click add to cart button - use force to bypass interceptors
    const addButton = firstRow.locator('.add-to-cart-btn').first();
    await expect(addButton).toBeVisible({ timeout: 5000 });
    await addButton.click({ force: true });
    printSuccess('Add to cart button clicked');
    
    // Wait for cart update - increased wait time for AJAX
    await page.waitForTimeout(3000);
    
    // Handle potential duplicate dialog
    const confirmBtn = page.locator('.swal2-confirm');
    try {
      if (await confirmBtn.isVisible({ timeout: 2000 })) {
        await confirmBtn.click({ force: true });
        await page.waitForTimeout(1000);
      }
    } catch {
      // No dialog appeared
    }
    
    // Verify cart count increased
    const cartCountAfter = await getCartItemCount(page);
    expect(cartCountAfter).toBeGreaterThan(cartCountBefore);
    printSuccess(`Cart items after: ${cartCountAfter}`);
  });
  
  test('Test Case 6: Test cart state changes', async ({ page }) => {
    printTestCase(6, 'Test Cart State Changes');
    
    const productsTable = page.locator('#productsTable');
    const firstRow = productsTable.locator('tbody tr:visible').first();
    
    // Add item to cart
    const qtyInput = firstRow.locator('.quantity-control input').first();
    await qtyInput.clear();
    await qtyInput.fill('3');
    
    const addButton = firstRow.locator('.add-to-cart-btn').first();
    await addButton.click();
    await page.waitForTimeout(2000);
    
    // Verify cart table is now visible
    const cartTable = page.locator('#cartTable');
    await expect(cartTable).toBeVisible({ timeout: 5000 });
    printSuccess('Cart table is visible after adding item');
    
    // Verify cart has at least one row
    const cartRows = cartTable.locator('tbody tr');
    const count = await cartRows.count();
    expect(count).toBeGreaterThan(0);
    printSuccess(`Cart contains ${count} item(s)`);
    
    // Verify cart total is displayed
    const totalElement = page.locator('#currentcartTotalPrice, [id*="cart-total"], .cart-total');
    const totalVisible = await totalElement.isVisible().catch(() => false);
    if (totalVisible) {
      const totalText = await totalElement.textContent();
      printSuccess(`Cart total displayed: ${totalText}`);
    } else {
      printWarning('Cart total element not found');
    }
  });
  
  test('Test Case 7: Test cart total calculations', async ({ page }) => {
    printTestCase(7, 'Test Cart Total Calculations');
    
    const productsTable = page.locator('#productsTable');
    
    // Step 1: Identify column indices by reading table headers
    const columnIndices = await productsTable.evaluate((table) => {
      const headers = Array.from(table.querySelectorAll('thead th'));
      const result: { priceExclIndex: number; priceInclIndex: number } = {
        priceExclIndex: -1,
        priceInclIndex: -1
      };
      
      headers.forEach((header, index) => {
        const text = header.textContent?.toLowerCase() || '';
        if (text.includes('price') && text.includes('excl')) {
          result.priceExclIndex = index;
        } else if (text.includes('price') && text.includes('incl')) {
          result.priceInclIndex = index;
        }
      });
      
      return result;
    });
    
    if (columnIndices.priceExclIndex === -1 || columnIndices.priceInclIndex === -1) {
      printWarning('Could not identify price columns in table headers');
      return;
    }
    
    printSuccess(`Price Excl column: ${columnIndices.priceExclIndex}, Price Incl column: ${columnIndices.priceInclIndex}`);
    
    // Step 2: Extract prices from the correct columns in the first data row
    // Note: Some columns may be hidden (display:none or d-none class), so we need to count only visible columns
    const firstRow = productsTable.locator('tbody tr:visible').first();
    const priceData = await firstRow.evaluate((row, indices) => {
      const allCells = Array.from(row.querySelectorAll('td'));
      
      // Filter to get only visible cells (matching visible headers)
      const visibleCells = allCells.filter(cell => {
        const style = window.getComputedStyle(cell);
        return style.display !== 'none';
      });
      
      // Debug: log all visible cell contents
      const cellContents = visibleCells.map((cell, i) => `[${i}]: ${cell.textContent?.trim().substring(0, 30)}`);
      
      if (visibleCells.length <= indices.priceInclIndex) {
        return {
          error: 'Not enough visible cells',
          cellCount: visibleCells.length,
          cellContents: cellContents
        };
      }
      
      const priceExclText = visibleCells[indices.priceExclIndex]?.textContent || '0';
      const priceInclText = visibleCells[indices.priceInclIndex]?.textContent || '0';
      
      return {
        priceExclVat: parseFloat(priceExclText.replace(/[^0-9.]/g, '')),
        priceInclVat: parseFloat(priceInclText.replace(/[^0-9.]/g, '')),
        priceExclText: priceExclText.trim(),
        priceInclText: priceInclText.trim(),
        cellCount: visibleCells.length,
        cellContents: cellContents
      };
    }, columnIndices);
    
    if (!priceData || priceData.error) {
      printWarning(`Could not extract price data: ${priceData?.error || 'unknown error'}`);
      return;
    }
    
    printSuccess(`Product Price Excl. VAT: ${priceData.priceExclText} (${priceData.priceExclVat.toFixed(2)})`);
    printSuccess(`Product Price Incl. VAT: ${priceData.priceInclText} (${priceData.priceInclVat.toFixed(2)})`);
    
    // Set quantity
    const quantity = 2;
    const qtyInput = firstRow.locator('.quantity-control input').first();
    await qtyInput.clear();
    await qtyInput.fill(quantity.toString());
    
    // Add to cart
    const addButton = firstRow.locator('.add-to-cart-btn').first();
    await addButton.click();
    await page.waitForTimeout(2000);
    
    // Calculate expected total (VAT inclusive) - compare incl to incl
    const expectedTotalInclVat = priceData.priceInclVat * quantity;
    printSuccess(`Expected total (incl. VAT): ${expectedTotalInclVat.toFixed(2)}`);
    
    // Get actual cart total (which is also VAT inclusive per #currentcartTotalPrice)
    const totalElement = page.locator('#currentcartTotalPrice, [id*="cart-total"], .cart-total').first();
    if (await totalElement.isVisible().catch(() => false)) {
      const totalText = await totalElement.textContent() || '0';
      const actualTotal = parseFloat(totalText.replace(/[^0-9.]/g, ''));
      printSuccess(`Actual total (incl. VAT): ${actualTotal.toFixed(2)}`);
      
      // Compare VAT-inclusive to VAT-inclusive - should match within rounding error
      const difference = Math.abs(actualTotal - expectedTotalInclVat);
      expect(difference).toBeLessThan(0.02);
      printSuccess('Cart total calculation is accurate (VAT incl. to VAT incl.)');
    } else {
      printWarning('Could not verify cart total - element not found');
    }
  });
  
  test('Test Case 8: Test duplicate item handling', async ({ page }) => {
    printTestCase(8, 'Test Duplicate Item Handling');
    
    const productsTable = page.locator('#productsTable');
    const firstRow = productsTable.locator('tbody tr:visible').first();
    
    // Add item once
    const qtyInput = firstRow.locator('.quantity-control input').first();
    await qtyInput.clear();
    await qtyInput.fill('1');
    await page.waitForTimeout(500);
    
    const addButton = firstRow.locator('.add-to-cart-btn').first();
    await addButton.click({ force: true });
    await page.waitForTimeout(3000);
    
    // Close any dialog that might have appeared
    await page.keyboard.press('Escape').catch(() => {});
    await page.waitForTimeout(500);
    
    printSuccess('First item added to cart');
    
    // Get cart count after first add
    const countAfterFirst = await getCartItemCount(page);
    
    // Try to add same item again
    await addButton.click({ force: true });
    await page.waitForTimeout(2000);
    
    // Check for SweetAlert modal
    const swalPopup = page.locator('.swal2-popup, .swal2-modal');
    const swalVisible = await swalPopup.isVisible().catch(() => false);
    
    if (swalVisible) {
      printSuccess('SweetAlert modal appeared for duplicate item');
      
      // Test "No" button (should not increase quantity)
      const cancelBtn = page.locator('.swal2-cancel, button:has-text("No")');
      if (await cancelBtn.isVisible().catch(() => false)) {
        await cancelBtn.click();
        await page.waitForTimeout(1000);
        
        const countAfterNo = await getCartItemCount(page);
        expect(countAfterNo).toBe(countAfterFirst);
        printSuccess('"No" button prevents adding duplicate');
        
        // Try adding again for "Yes" test
        await addButton.click();
        await page.waitForTimeout(1000);
      }
      
      // Test "Yes" button (should increase quantity)
      const confirmBtn = page.locator('.swal2-confirm, button:has-text("Yes")');
      if (await confirmBtn.isVisible().catch(() => false)) {
        await confirmBtn.click();
        await page.waitForTimeout(1000);
        
        printSuccess('"Yes" button clicked to add duplicate');
      }
    } else {
      printWarning('No SweetAlert modal for duplicate - may be auto-added');
    }
  });
  
  test('Test Case 9: Verify cart data accuracy', async ({ page }) => {
    printTestCase(9, 'Verify Cart Data Accuracy');
    
    const productsTable = page.locator('#productsTable');
    const firstRow = productsTable.locator('tbody tr:visible').first();
    
    // Get product details from products table
    const productName = await firstRow.locator('td').first().textContent() || '';
    const priceCell = firstRow.locator('td').filter({ hasText: /₡\s*\d|R\s*\d|[£$€]\s*\d/ });
    const priceText = await priceCell.first().textContent() || '0';
    const expectedPrice = parseFloat(priceText.replace(/[^0-9.]/g, ''));
    
    printSuccess(`Product: ${productName.trim()}`);
    printSuccess(`Expected price: ${expectedPrice}`);
    
    // Add to cart
    const qtyInput = firstRow.locator('.quantity-control input').first();
    await qtyInput.clear();
    await qtyInput.fill('2');
    const expectedQty = await qtyInput.inputValue();
    
    const addButton = firstRow.locator('.add-to-cart-btn').first();
    await addButton.click();
    await page.waitForTimeout(2000);
    
    // Verify cart data
    const cartTable = page.locator('#cartTable');
    const cartRow = cartTable.locator('tbody tr').first();
    
    const cartProductName = await cartRow.locator('td').first().textContent() || '';
    printSuccess(`Cart product: ${cartProductName.trim()}`);
    
    // Verify quantity in cart
    const cartQtyInput = cartRow.locator('.quantity-control input');
    if (await cartQtyInput.isVisible().catch(() => false)) {
      const cartQty = await cartQtyInput.inputValue();
      expect(cartQty).toBe(expectedQty);
      printSuccess(`Cart quantity matches: ${cartQty}`);
    }
  });
  
  test('Test Case 10: Test business rules', async ({ page }) => {
    printTestCase(10, 'Test Business Rules');
    
    const productsTable = page.locator('#productsTable');
    const firstRow = productsTable.locator('tbody tr:visible').first();
    
    // Test VAT calculation (if applicable)
    const priceCell = firstRow.locator('td').filter({ hasText: /₡\s*\d|R\s*\d|[£$€]\s*\d/ });
    const priceText = await priceCell.first().textContent() || '';
    
    // Verify currency symbol present
    const hasCurrency = /₡|R|[£$€]/.test(priceText);
    if (hasCurrency) {
      printSuccess(`Currency symbol found in price: ${priceText}`);
    } else {
      printWarning('Currency symbol not clearly visible');
    }
    
    // Verify price format is valid number
    const price = parseFloat(priceText.replace(/[^0-9.]/g, ''));
    expect(price).toBeGreaterThan(0);
    printSuccess(`Valid price format: ${price}`);
    
    // Test minimum quantity enforcement
    const qtyInput = firstRow.locator('.quantity-control input').first();
    const minQty = await qtyInput.getAttribute('min');
    if (minQty) {
      printSuccess(`Minimum quantity enforced: ${minQty}`);
    }
    
    // Test maximum quantity (if applicable)
    const maxQty = await qtyInput.getAttribute('max');
    if (maxQty) {
      printSuccess(`Maximum quantity enforced: ${maxQty}`);
    }
    
    // Verify VAT calculation if VAT element exists
    const vatElement = page.locator('[id*="vat"], [class*="vat"], td:has-text("VAT")');
    if (await vatElement.isVisible().catch(() => false)) {
      const vatText = await vatElement.textContent();
      printSuccess(`VAT information found: ${vatText}`);
    } else {
      printWarning('VAT element not found - may be included in price');
    }
  });
  
  test('Test Case 11: Test cleanup functionality', async ({ page }) => {
    printTestCase(11, 'Test Cleanup Functionality');
    
    const productsTable = page.locator('#productsTable');
    const firstRow = productsTable.locator('tbody tr:visible').first();
    
    // Add items to cart
    const qtyInput = firstRow.locator('.quantity-control input').first();
    await qtyInput.clear();
    await qtyInput.fill('1');
    
    const addButton = firstRow.locator('.add-to-cart-btn').first();
    await addButton.click();
    
    // Handle potential "increase quantity" modal
    await handleIncreaseQuantityModal(page, 'cancel');
    
    await page.waitForTimeout(2000);
    
    // Verify cart has items
    let cartCount = await getCartItemCount(page);
    expect(cartCount).toBeGreaterThan(0);
    printSuccess(`Cart has ${cartCount} items before cleanup`);
    
    // Test cleanup
    await clearCart(page);
    await page.waitForTimeout(2000);
    
    // Verify cart is empty
    cartCount = await getCartItemCount(page);
    expect(cartCount).toBe(0);
    printSuccess('Cart cleanup successful - cart is empty');
  });
});

