/**
 * CRUD Helper for cPad module tests.
 *
 * Provides reusable functions that detect and execute common CRUD operations
 * (Create, Edit, Delete) through the cPad UI without hard-coding selectors
 * for every individual module.
 *
 * Strategy:
 *  • "Create" — look for button text: Create / Add / New
 *  • "Edit"   — look for button/link text: Edit, or table action icons
 *  • "Delete" — look for button/link text: Delete / Remove (with confirmation handling)
 *
 * Each function returns false if the appropriate trigger could not be found,
 * allowing callers to skip gracefully when a module lacks a given operation.
 */

import { type Page, expect } from '@playwright/test';
import { fillForm } from './formFiller';

// Selectors used to locate CRUD triggers (order = priority)
const CREATE_SELECTORS = [
  'a:has-text("Create")',
  'a:has-text("Add")',
  'a:has-text("New")',
  'button:has-text("Create")',
  'button:has-text("Add")',
  'button:has-text("New")',
  '[data-testid="btn-create"]',
  '[data-testid="btn-add"]',
];

const EDIT_SELECTORS = [
  'a:has-text("Edit")',
  'button:has-text("Edit")',
  'td a[href*="/edit/"]',
  '[data-testid="btn-edit"]',
];

const DELETE_SELECTORS = [
  'a:has-text("Delete")',
  'button:has-text("Delete")',
  'a:has-text("Remove")',
  'button:has-text("Remove")',
  '[data-testid="btn-delete"]',
];

/**
 * Try to find and click a Create/Add/New button, fill the resulting form,
 * submit it, and verify the page does not show a 500 error.
 *
 * @returns true if a create button was found and the flow completed without crashing.
 */
export async function tryCrudCreate(page: Page): Promise<boolean> {
  for (const selector of CREATE_SELECTORS) {
    const btn = page.locator(selector).first();
    if (await btn.count() > 0 && await btn.isVisible()) {
      await btn.click();

      // Wait for either a form or a new page section to appear
      await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => null);

      // Fill any visible form
      await fillForm(page);

      // Look for a submit button
      const submit = page.locator('button[type=submit], input[type=submit]').first();
      if (await submit.count() > 0 && await submit.isVisible()) {
        await submit.click();
        await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => null);

        // Fail if a Laravel/server error page appeared
        const body = await page.locator('body').textContent() ?? '';
        const hasServerError = /Whoops|Server Error|500|SQLSTATE|Call to undefined/i.test(body);
        expect(hasServerError, `Server error after create on ${page.url()}`).toBe(false);
      }

      return true;
    }
  }
  return false;
}

/**
 * Try to find and click the first Edit button/link on the page, fill the form,
 * and submit.
 *
 * @returns true if an edit trigger was found.
 */
export async function tryCrudEdit(page: Page): Promise<boolean> {
  for (const selector of EDIT_SELECTORS) {
    const btn = page.locator(selector).first();
    if (await btn.count() > 0 && await btn.isVisible()) {
      await btn.click();
      await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => null);

      await fillForm(page);

      const submit = page.locator('button[type=submit], input[type=submit]').first();
      if (await submit.count() > 0 && await submit.isVisible()) {
        await submit.click();
        await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => null);

        const body = await page.locator('body').textContent() ?? '';
        const hasServerError = /Whoops|Server Error|500|SQLSTATE|Call to undefined/i.test(body);
        expect(hasServerError, `Server error after edit on ${page.url()}`).toBe(false);
      }

      return true;
    }
  }
  return false;
}

/**
 * Try to click the first delete trigger, handle a confirmation dialog if one
 * appears, and assert no server error is displayed.
 *
 * @returns true if a delete trigger was found.
 */
export async function tryCrudDelete(page: Page): Promise<boolean> {
  for (const selector of DELETE_SELECTORS) {
    const btn = page.locator(selector).first();
    if (await btn.count() > 0 && await btn.isVisible()) {
      // Some delete links pop a browser confirm() dialog
      page.once('dialog', (dialog) => dialog.accept());

      await btn.click();
      await page.waitForLoadState('networkidle', { timeout: 10_000 }).catch(() => null);

      const body = await page.locator('body').textContent() ?? '';
      const hasServerError = /Whoops|Server Error|500|SQLSTATE|Call to undefined/i.test(body);
      expect(hasServerError, `Server error after delete on ${page.url()}`).toBe(false);

      return true;
    }
  }
  return false;
}

/**
 * Quick check whether the page contains any list/table data (i.e. the module
 * has records to operate on).
 */
export async function hasListData(page: Page): Promise<boolean> {
  const tableRows = await page.locator('table tbody tr').count();
  return tableRows > 0;
}
