/**
 * Navigation Discovery — scans the cPad sidebar and collects all /cp links.
 *
 * This test acts as both:
 *   1. A standalone spec that validates the nav scan returns ≥ 1 link.
 *   2. A data producer: it writes the discovered URLs to
 *      tests/.discovered/cpad-links.json so that navigation.spec.ts can
 *      consume them dynamically.
 *
 * Ignored links:
 *   • /cp/logout
 *   • javascript:void / # anchors
 *   • External URLs (not starting with /cp)
 *
 * Run:
 *   npx playwright test tests/cpad/navigation-discovery.spec.ts --project=cpad
 */

import { test, expect } from '@playwright/test';
import { DASHBOARD_PATH, CP_PATH } from '../helpers/auth';
import fs from 'fs';
import path from 'path';

const DISCOVERED_DIR  = path.join('tests', '.discovered');
const DISCOVERED_FILE = path.join(DISCOVERED_DIR, 'cpad-links.json');

// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────

/** Returns true if the href should be included in navigation tests */
function isNavigableLink(href: string | null): boolean {
  if (!href) return false;
  if (!href.startsWith(CP_PATH)) return false;
  if (href.includes('/logout')) return false;
  if (href.startsWith('javascript:')) return false;
  if (href === CP_PATH || href === CP_PATH + '/') return false;   // exclude root (same as dashboard)
  return true;
}

/** Remove query strings and anchors for clean deduplication */
function normalise(href: string): string {
  try {
    const u = new URL(href, 'http://placeholder');
    return u.pathname;
  } catch {
    return href.split('?')[0].split('#')[0];
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Discovery test
// ─────────────────────────────────────────────────────────────────────────────

test.describe('cPad Navigation Discovery', () => {
  test('scan sidebar and collect all /cp navigation links', async ({ page }) => {
    await page.goto(DASHBOARD_PATH);
    await page.waitForLoadState('networkidle');

    // Ensure we're not on the login page
    expect(page.url()).not.toContain('/login');

    // ── Widen the scan to cover lazy-loaded submenu items ──────────────────
    // Hover over sidebar nav items to expand hidden submenus
    const menuItems = page.locator('.nav-item, .sidebar-item, .menu-item, li.nav-item');
    const menuCount = await menuItems.count();
    for (let i = 0; i < Math.min(menuCount, 30); i++) {
      await menuItems.nth(i).hover().catch(() => null);
    }

    // ── Collect all anchor hrefs ───────────────────────────────────────────
    const rawHrefs: string[] = await page.$$eval('a[href]', (anchors) =>
      anchors.map((a) => (a as HTMLAnchorElement).getAttribute('href') ?? ''),
    );

    const discovered = [...new Set(
      rawHrefs
        .map((h) => normalise(h))
        .filter(isNavigableLink),
    )].sort();

    console.log(`[discovery] Found ${discovered.length} navigable /cp links`);
    discovered.forEach((l) => console.log('  •', l));

    // Must find at least a few links — if not, something is wrong with auth
    expect(discovered.length, 'Expected to find /cp navigation links').toBeGreaterThanOrEqual(1);

    // ── Persist for navigation.spec.ts ────────────────────────────────────
    if (!fs.existsSync(DISCOVERED_DIR)) {
      fs.mkdirSync(DISCOVERED_DIR, { recursive: true });
    }
    fs.writeFileSync(DISCOVERED_FILE, JSON.stringify(discovered, null, 2), 'utf8');
    console.log(`[discovery] Links saved to ${DISCOVERED_FILE}`);
  });
});
