/**
 * Workflow Verification: UXB-301 — Collapsed 3-way label drift on notification-settings.show
 * Session: 7e423795-dcf2-40ce-8fd1-090a7c8bd86d
 *
 * Changed files:
 *   - resources/js/Layouts/DashboardLayout.tsx
 *   - resources/js/Pages/Settings/Notifications.tsx
 *
 * Flows verified:
 *   1. Golden path: user-menu item reads 'Alert Subscriptions' (not 'Notifications')
 *   2. Page Head <title> includes 'Alert Subscriptions'
 *   3. Page h1 / EditorialPageHeader title reads 'Alert Subscriptions'
 *   4. Page loads without JS errors or failed XHR
 *   5. Unauthenticated access redirects to login
 *
 * Human success check:
 *   user-menu item, page Head title, and page h1 all read 'Alert Subscriptions'
 */

import { execSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';

import { expect, test } from '../fixtures/auth';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const CANONICAL_LABEL = 'Alert Subscriptions';

/**
 * Run PHP code via artisan tinker (same pattern as roi-dashboard spec).
 * Writes code to a temp file to avoid shell-escaping issues.
 */
function runPhp(phpCode: string): string {
  const tmpFile = path.join('/tmp', `e2e_uxb301_${process.pid}_${Date.now()}.php`);
  try {
    fs.writeFileSync(tmpFile, phpCode, 'utf8');
    return execSync(`php artisan tinker --execute="$(cat ${tmpFile})" 2>&1`, {
      cwd: process.cwd(),
      encoding: 'utf8',
      timeout: 30_000,
      shell: '/bin/bash',
    });
  } finally {
    try {
      fs.unlinkSync(tmpFile);
    } catch {
      /* ignore cleanup errors */
    }
  }
}

/**
 * Resolve the Site's ULID public_id from the integer seed siteId.
 * Site uses HasPublicId so URL segments are ULIDs, not integer PKs.
 */
function resolveSitePublicId(siteId: number): string {
  const raw = runPhp(
    `$s = \\App\\Models\\Site::find(${siteId}); echo $s ? $s->public_id : 'NOT_FOUND';`,
  );
  const result = raw
    .trim()
    .split('\n')
    .map((l) => l.trim())
    .filter(Boolean)
    .pop() ?? '';
  if (!result || result === 'NOT_FOUND') {
    throw new Error(`resolveSitePublicId(${siteId}) failed. Raw:\n${raw}`);
  }
  return result;
}

// Resolve once at module load (global-setup has already seeded the DB)
const seedDataPath = path.join(__dirname, '..', '.seed-data.json');
const seedJson = JSON.parse(fs.readFileSync(seedDataPath, 'utf8')) as { siteId: number };
const sitePublicId = resolveSitePublicId(seedJson.siteId);
const NOTIFICATION_SETTINGS_URL = `/sites/${sitePublicId}/notification-settings`;

test.describe('Workflow: UXB-301 — Alert Subscriptions label consistency (7e423795)', () => {
  test.describe('User-menu label', () => {
    test('user-menu item reads "Alert Subscriptions" when feature is enabled', async ({ page }) => {
      const errors: string[] = [];
      page.on('pageerror', (err) => errors.push(err.message));

      // Navigate to the notification settings page (provides a site-context layout)
      await page.goto(NOTIFICATION_SETTINGS_URL, { waitUntil: 'networkidle' });

      // Open the user-menu dropdown — aria-label matches DashboardLayout line 543
      const userMenuTrigger = page.getByRole('button', { name: 'User menu' });
      await expect(userMenuTrigger).toBeVisible();
      await userMenuTrigger.click();

      // The Alert Subscriptions menu item is gated on FEATURE_NOTIFICATIONS.
      // In dev/.env FEATURE_NOTIFICATIONS may be false (item hidden) or true (item shown).
      // When visible: assert canonical label. When not visible: assert old label absent.
      const menuItem = page.getByRole('menuitem', { name: CANONICAL_LABEL });
      const oldLabelAsMenuItem = page
        .getByRole('menu')
        .getByRole('menuitem', { name: /^Notifications$/, exact: true });

      const menuVisible = await menuItem.isVisible().catch(() => false);
      if (menuVisible) {
        // FEATURE_NOTIFICATIONS=true path: canonical label must be present
        await expect(menuItem).toBeVisible();
      }
      // In either case: old bare 'Notifications' label must NOT appear as the menu item
      await expect(oldLabelAsMenuItem).toHaveCount(0);

      const appErrors = errors.filter(
        (e) =>
          !e.includes('extension') &&
          !e.includes('chrome-extension') &&
          !e.includes('favicon'),
      );
      expect(appErrors, `Console errors: ${appErrors.join('\n')}`).toHaveLength(0);
    });
  });

  test.describe('Page Head title', () => {
    test('page <title> contains "Alert Subscriptions"', async ({ page }) => {
      await page.goto(NOTIFICATION_SETTINGS_URL, { waitUntil: 'networkidle' });

      await expect(page).toHaveTitle(new RegExp(CANONICAL_LABEL, 'i'));
    });

    test('page <title> does NOT match old drifted label pattern', async ({ page }) => {
      await page.goto(NOTIFICATION_SETTINGS_URL, { waitUntil: 'networkidle' });

      const title = await page.title();
      // The old drifted title was "Notifications - <site>" — assert it's now the canonical label
      expect(title).toMatch(/Alert Subscriptions/i);
      expect(title).not.toMatch(/^Notifications\s*[-–]/);
    });
  });

  test.describe('Page h1 / EditorialPageHeader', () => {
    test('h1 / page heading reads "Alert Subscriptions"', async ({ page }) => {
      await page.goto(NOTIFICATION_SETTINGS_URL, { waitUntil: 'networkidle' });

      // EditorialPageHeader renders the title prop as a prominent heading element
      const heading = page.getByRole('heading', { name: CANONICAL_LABEL });
      await expect(heading.first()).toBeVisible();
    });

    test('heading does NOT display old drifted label "Notifications"', async ({ page }) => {
      await page.goto(NOTIFICATION_SETTINGS_URL, { waitUntil: 'networkidle' });

      // No heading element should carry the bare 'Notifications' text
      const oldHeading = page.getByRole('heading', { name: /^Notifications$/, exact: true });
      await expect(oldHeading).toHaveCount(0);
    });
  });

  test.describe('Page health', () => {
    test('renders without JS errors', async ({ page }) => {
      const errors: string[] = [];
      page.on('pageerror', (err) => errors.push(err.message));
      page.on('console', (msg) => {
        if (msg.type() === 'error') errors.push(msg.text());
      });

      await page.goto(NOTIFICATION_SETTINGS_URL, { waitUntil: 'networkidle' });

      const appErrors = errors.filter(
        (e) =>
          !e.includes('extension') &&
          !e.includes('chrome-extension') &&
          !e.includes('favicon') &&
          !e.includes('ERR_TOO_MANY_REDIRECTS'),
      );
      expect(appErrors, `Console errors: ${appErrors.join('\n')}`).toHaveLength(0);
    });

    test('shows no failed XHR (4xx/5xx) on page load', async ({ page }) => {
      const failedRequests: string[] = [];
      page.on('response', (response) => {
        const status = response.status();
        const url = response.url();
        if (status >= 400 && !url.includes('favicon')) {
          failedRequests.push(`${status} ${url}`);
        }
      });

      await page.goto(NOTIFICATION_SETTINGS_URL, { waitUntil: 'networkidle' });

      expect(
        failedRequests,
        `Failed XHR requests: ${failedRequests.join('\n')}`,
      ).toHaveLength(0);
    });

    test('page form and Save Settings button are present', async ({ page }) => {
      await page.goto(NOTIFICATION_SETTINGS_URL, { waitUntil: 'networkidle' });

      await expect(page.getByRole('button', { name: /save settings/i })).toBeVisible();
    });
  });

  test.describe('Unauthenticated access', () => {
    test('redirects to login when not authenticated', async ({ browser }) => {
      const context = await browser.newContext({ storageState: { cookies: [], origins: [] } });
      const page = await context.newPage();

      await page.goto(`http://localhost:8000${NOTIFICATION_SETTINGS_URL}`);
      await expect(page).toHaveURL(/\/login/);

      await context.close();
    });
  });
});
