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

/**
 * AccountingCore E2E Test Helpers
 */

// ============================================
// Authentication
// ============================================

/**
 * Login as admin user
 */
export async function loginAsAdmin(page: Page) {
  await page.goto('/auth/login', { waitUntil: 'networkidle' });
  await page.locator('#email').fill('admin@demo.com');
  await page.locator('#password').fill('password123');
  await page.locator('button[type="submit"]').click();
  await page.waitForURL('**/dashboard', { timeout: 15000 });
}

// ============================================
// Navigation Helpers
// ============================================

/**
 * Navigate to AccountingCore dashboard
 */
export async function navigateToAccountingDashboard(page: Page) {
  await page.goto('/accountingcore/dashboard', { waitUntil: 'networkidle' });
  await waitForPageStable(page);
}

/**
 * Navigate to categories list
 */
export async function navigateToCategories(page: Page) {
  await page.goto('/accountingcore/categories', { waitUntil: 'networkidle' });
  await waitForPageStable(page);
}

/**
 * Navigate to transactions list
 */
export async function navigateToTransactions(page: Page) {
  await page.goto('/accountingcore/transactions', { waitUntil: 'networkidle' });
  await waitForPageStable(page);
}

/**
 * Navigate to reports page
 */
export async function navigateToReports(page: Page) {
  await page.goto('/accountingcore/reports', { waitUntil: 'networkidle' });
  await waitForPageStable(page);
}

/**
 * Navigate to summary report
 */
export async function navigateToSummaryReport(page: Page) {
  await page.goto('/accountingcore/reports/summary', { waitUntil: 'networkidle' });
  await waitForPageStable(page);
}

/**
 * Navigate to cash flow report
 */
export async function navigateToCashFlowReport(page: Page) {
  await page.goto('/accountingcore/reports/cashflow', { waitUntil: 'networkidle' });
  await waitForPageStable(page);
}

/**
 * Navigate to category performance report
 */
export async function navigateToCategoryPerformanceReport(page: Page) {
  await page.goto('/accountingcore/reports/category-performance', { waitUntil: 'networkidle' });
  await waitForPageStable(page);
}

/**
 * Navigate to settings page
 */
export async function navigateToSettings(page: Page) {
  await page.goto('/accountingcore/settings', { waitUntil: 'networkidle' });
  await waitForPageStable(page);
}

// ============================================
// Page Stability Helpers
// ============================================

/**
 * Wait for page to be stable (no pending network requests, animations complete)
 */
export async function waitForPageStable(page: Page) {
  await page.waitForLoadState('networkidle');
  await page.waitForTimeout(500);
}

/**
 * Wait for DataTable to load
 */
export async function waitForDataTable(page: Page) {
  await page.waitForSelector('table tbody tr', { timeout: 10000 });
  await page.waitForTimeout(500);
}

/**
 * Wait for offcanvas to open
 */
export async function waitForOffcanvasOpen(page: Page) {
  await page.waitForSelector('.offcanvas.show', { state: 'visible', timeout: 5000 });
  await page.waitForTimeout(300);
}

/**
 * Wait for offcanvas to close
 */
export async function waitForOffcanvasClose(page: Page) {
  await page.waitForSelector('.offcanvas.show', { state: 'hidden', timeout: 5000 });
  await page.waitForTimeout(300);
}

// ============================================
// SweetAlert2 Helpers
// ============================================

/**
 * Confirm a SweetAlert2 dialog
 */
export async function confirmSweetAlert(page: Page) {
  await page.waitForSelector('.swal2-popup', { state: 'visible', timeout: 5000 });
  await page.locator('.swal2-confirm').click();
  await page.waitForTimeout(500);
}

/**
 * Cancel a SweetAlert2 dialog
 */
export async function cancelSweetAlert(page: Page) {
  await page.waitForSelector('.swal2-popup', { state: 'visible', timeout: 5000 });
  await page.locator('.swal2-cancel').click();
  await page.waitForTimeout(500);
}

/**
 * Wait for success SweetAlert2 and dismiss it
 */
export async function waitForSuccessSweetAlert(page: Page) {
  await page.waitForSelector('.swal2-popup', { state: 'visible', timeout: 10000 });
  await expect(page.locator('.swal2-icon.swal2-success')).toBeVisible({ timeout: 5000 });

  // Try to click confirm button if it exists and is visible
  const confirmButton = page.locator('.swal2-confirm');
  try {
    // Wait a brief moment for the button to be clickable
    await confirmButton.waitFor({ state: 'visible', timeout: 2000 });
    await confirmButton.click({ timeout: 2000 });
  } catch {
    // SweetAlert might auto-dismiss with timer, that's OK
  }

  // Wait for popup to close (either by click or timer)
  await page.waitForSelector('.swal2-popup', { state: 'hidden', timeout: 10000 });
  await page.waitForTimeout(300);
}

/**
 * Wait for error SweetAlert2
 */
export async function waitForErrorSweetAlert(page: Page) {
  await page.waitForSelector('.swal2-popup', { state: 'visible', timeout: 10000 });
  await expect(page.locator('.swal2-icon.swal2-error')).toBeVisible({ timeout: 5000 });
}

// ============================================
// Form Helpers
// ============================================

/**
 * Fill Select2 dropdown by ID
 */
export async function fillSelect2ById(page: Page, selectId: string, searchText: string) {
  // Close any open dropdowns first
  await page.keyboard.press('Escape');
  await page.waitForTimeout(200);

  // Click on Select2 container
  const select2Container = page.locator(`#${selectId}`).locator('..').locator('.select2-container');

  // If no Select2 container, try clicking the select directly (for native select with Select2)
  const containerExists = await select2Container.count() > 0;
  if (containerExists) {
    await select2Container.click();
  } else {
    // Try the sibling selector pattern
    const siblingContainer = page.locator(`#${selectId} + .select2-container, #${selectId} ~ .select2-container`).first();
    await siblingContainer.click();
  }

  await page.waitForTimeout(300);

  // Wait for dropdown to appear
  await page.waitForSelector('.select2-dropdown', { state: 'visible', timeout: 5000 });

  // Type in search field if available
  const searchInput = page.locator('.select2-search__field');
  if (await searchInput.isVisible()) {
    await searchInput.fill(searchText);
    await page.waitForTimeout(500);
  }

  // Wait for and click first result
  await page.waitForSelector('.select2-results__option:not(.loading-results)', { timeout: 5000 });
  await page.locator('.select2-results__option').first().click();
  await page.waitForTimeout(200);
}

/**
 * Set date using Flatpickr
 */
export async function setFlatpickrDate(page: Page, selector: string, date: string) {
  await page.evaluate(([sel, val]) => {
    const input = document.querySelector(sel) as HTMLInputElement;
    if (input) {
      const fp = (input as any)._flatpickr;
      if (fp) {
        fp.setDate(val, true);
      } else {
        input.value = val;
        input.dispatchEvent(new Event('change', { bubbles: true }));
      }
    }
  }, [selector, date]);
  await page.waitForTimeout(200);
}

/**
 * Select option from native select dropdown
 */
export async function selectOption(page: Page, selector: string, value: string) {
  await page.locator(selector).selectOption(value);
  await page.waitForTimeout(200);
}

// ============================================
// Category Helpers
// ============================================

interface CategoryOptions {
  parentId?: string;
  icon?: string;
  color?: string;
  isActive?: boolean;
}

/**
 * Create a new category
 */
export async function createCategory(
  page: Page,
  name: string,
  type: 'income' | 'expense',
  options?: CategoryOptions
) {
  // Click Add Category button
  const addButton = page.locator('button:has-text("Add"), button:has-text("New Category")').first();
  await addButton.click();
  await waitForOffcanvasOpen(page);

  // Fill required fields
  await page.locator('#name').fill(name);
  await page.locator('#type').selectOption(type);

  // Fill optional fields
  if (options?.icon) {
    await page.locator('#icon').fill(options.icon);
  }
  if (options?.color) {
    // Color inputs need special handling - use evaluate to set value
    await page.evaluate((color) => {
      const colorInput = document.querySelector('#color') as HTMLInputElement;
      if (colorInput) {
        colorInput.value = color;
        colorInput.dispatchEvent(new Event('change', { bubbles: true }));
      }
    }, options.color);
  }
  if (options?.isActive === false) {
    await page.locator('#is_active').uncheck();
  }

  // Submit form
  const submitButton = page.locator('.offcanvas.show button[type="submit"]').first();
  await submitButton.click();
  await waitForSuccessSweetAlert(page);
}

/**
 * Delete a category from the list
 */
export async function deleteCategory(page: Page, categoryName: string) {
  const row = page.locator('table tbody tr').filter({ hasText: categoryName }).first();

  // Handle responsive DataTable
  const expandControl = row.locator('.dtr-control, td.dtr-control').first();
  if (await expandControl.count() > 0 && await expandControl.isVisible()) {
    await expandControl.click();
    await page.waitForTimeout(300);
  }

  // Click dropdown toggle
  let dropdownToggle = row.locator('.dropdown-toggle, button.btn-icon').first();
  if (!await dropdownToggle.isVisible()) {
    const childRow = page.locator('table tbody tr.child').first();
    if (await childRow.count() > 0) {
      dropdownToggle = childRow.locator('.dropdown-toggle, button.btn-icon').first();
    }
  }
  await dropdownToggle.click({ force: true });
  await page.waitForTimeout(300);

  // Click delete action
  const deleteButton = page.locator('.dropdown-menu.show .dropdown-item:has-text("Delete")').first();
  await deleteButton.click();
  await page.waitForTimeout(300);

  // Confirm deletion
  await confirmSweetAlert(page);
  await waitForSuccessSweetAlert(page);
}

// ============================================
// Transaction Helpers
// ============================================

interface TransactionOptions {
  referenceNumber?: string;
  paymentMethod?: string;
  tags?: string[];
  attachmentPath?: string;
}

/**
 * Create a new transaction
 */
export async function createTransaction(
  page: Page,
  type: 'income' | 'expense',
  amount: string,
  categoryName: string,
  description: string,
  transactionDate: string,
  options?: TransactionOptions
) {
  // Click Add Transaction button
  const addButton = page.locator('a[href*="transactions/create"], button:has-text("Add"), button:has-text("New Transaction")').first();
  await addButton.click();

  // Wait for form (could be offcanvas or page)
  await page.waitForTimeout(500);
  await waitForPageStable(page);

  // Fill required fields
  await page.locator('#type').selectOption(type);
  await page.waitForTimeout(300); // Wait for category filter to update

  await page.locator('#amount').fill(amount);
  await setFlatpickrDate(page, '#transaction_date', transactionDate);
  await page.locator('#description').fill(description);

  // Select category (may be filtered by type)
  await fillSelect2ById(page, 'category_id', categoryName);

  // Fill optional fields
  if (options?.referenceNumber) {
    await page.locator('#reference_number').fill(options.referenceNumber);
  }
  if (options?.paymentMethod) {
    await page.locator('#payment_method').selectOption(options.paymentMethod);
  }

  // Submit form
  const submitButton = page.locator('button[type="submit"]').first();
  await submitButton.click();
  await waitForSuccessSweetAlert(page);
}

/**
 * Delete a transaction
 */
export async function deleteTransaction(page: Page, rowIndex: number = 0) {
  const rows = page.locator('table tbody tr:not(.child)');
  const row = rows.nth(rowIndex);

  // Handle responsive DataTable
  const expandControl = row.locator('.dtr-control, td.dtr-control').first();
  if (await expandControl.count() > 0 && await expandControl.isVisible()) {
    await expandControl.click();
    await page.waitForTimeout(300);
  }

  // Click dropdown toggle
  let dropdownToggle = row.locator('.dropdown-toggle, button.btn-icon').first();
  if (!await dropdownToggle.isVisible()) {
    const childRow = page.locator('table tbody tr.child').first();
    if (await childRow.count() > 0) {
      dropdownToggle = childRow.locator('.dropdown-toggle, button.btn-icon').first();
    }
  }
  await dropdownToggle.click({ force: true });
  await page.waitForTimeout(300);

  // Click delete action
  const deleteButton = page.locator('.dropdown-menu.show .dropdown-item:has-text("Delete")').first();
  await deleteButton.click();
  await page.waitForTimeout(300);

  // Confirm deletion
  await confirmSweetAlert(page);
  await waitForSuccessSweetAlert(page);
}

/**
 * Click table action (View, Edit, Delete) on a row
 */
export async function clickTableAction(page: Page, rowIndex: number, actionName: string) {
  const rows = page.locator('table tbody tr:not(.child)');
  const row = rows.nth(rowIndex);

  // Handle responsive DataTable - check if actions are in collapsed column
  const expandControl = row.locator('.dtr-control, td.dtr-control').first();
  if (await expandControl.count() > 0 && await expandControl.isVisible()) {
    await expandControl.click();
    await page.waitForTimeout(300);
  }

  // Try to find dropdown toggle in main row or expanded child row
  let actionDropdown = row.locator('.dropdown-toggle, button.btn-icon, button[data-bs-toggle="dropdown"]').first();

  if (!await actionDropdown.isVisible()) {
    // Check in child row (expanded responsive content)
    const childRow = page.locator('table tbody tr.child').first();
    if (await childRow.count() > 0) {
      actionDropdown = childRow.locator('.dropdown-toggle, button.btn-icon, button[data-bs-toggle="dropdown"]').first();
    }
  }

  // If still not visible, try looking for any dropdown toggle in the row
  if (!await actionDropdown.isVisible()) {
    actionDropdown = row.locator('[data-bs-toggle="dropdown"]').first();
  }

  await actionDropdown.click({ force: true });
  await page.waitForTimeout(500);

  // Wait for dropdown menu to appear
  await page.waitForSelector('.dropdown-menu.show', { state: 'visible', timeout: 5000 });

  // Click the specific action - try multiple selector patterns
  let actionButton = page.locator('.dropdown-menu.show').locator(`.dropdown-item:has-text("${actionName}")`).first();
  if (!await actionButton.isVisible()) {
    actionButton = page.locator('.dropdown-menu.show').locator(`a:has-text("${actionName}")`).first();
  }
  if (!await actionButton.isVisible()) {
    actionButton = page.locator('.dropdown-menu.show').locator(`button:has-text("${actionName}")`).first();
  }

  await actionButton.click({ force: true });
  await page.waitForTimeout(300);
}

// ============================================
// Date Utilities
// ============================================

/**
 * Get today's date in YYYY-MM-DD format
 */
export function getTodayDate(): string {
  const today = new Date();
  return today.toISOString().split('T')[0];
}

/**
 * Get a past date in YYYY-MM-DD format
 */
export function getPastDate(daysAgo: number): string {
  const date = new Date();
  date.setDate(date.getDate() - daysAgo);
  return date.toISOString().split('T')[0];
}

/**
 * Get a future date in YYYY-MM-DD format
 */
export function getFutureDate(daysAhead: number): string {
  const date = new Date();
  date.setDate(date.getDate() + daysAhead);
  return date.toISOString().split('T')[0];
}

/**
 * Get first day of current month in YYYY-MM-DD format
 */
export function getFirstDayOfMonth(): string {
  const date = new Date();
  date.setDate(1);
  return date.toISOString().split('T')[0];
}

/**
 * Get last day of current month in YYYY-MM-DD format
 */
export function getLastDayOfMonth(): string {
  const date = new Date();
  date.setMonth(date.getMonth() + 1);
  date.setDate(0);
  return date.toISOString().split('T')[0];
}

// ============================================
// Unique Data Generation
// ============================================

/**
 * Generate unique category name
 */
export function generateUniqueCategoryName(): string {
  return `Test Category ${Date.now().toString().slice(-6)}`;
}

/**
 * Generate unique transaction reference
 */
export function generateUniqueReference(): string {
  return `REF-${Date.now().toString().slice(-8)}`;
}

/**
 * Generate random amount between min and max
 */
export function generateRandomAmount(min: number = 100, max: number = 10000): string {
  const amount = Math.floor(Math.random() * (max - min + 1)) + min;
  return amount.toFixed(2);
}
