/**
 * Workflow: Site Settings — General
 *
 * Scope: resources/js/Pages/Sites/Settings/General.tsx
 *        resources/js/Components/Shared/SiteSetupChecklist.tsx (orphaned — not rendered in any
 *        page as of this session; browser-exercisable path does not exist; component correctness
 *        covered by unit tests.)
 *
 * Session: e0a0b5cb-5cef-42b8-b669-e37c160b06a2
 *
 * === public_id routing ===
 * All user-facing routes bind via HasPublicId (ULID). Site public_id is resolved
 * from the seed data integer ID via artisan tinker before tests run (same pattern
 * used by freshness-r9fe105, pd-001-entry-verb, and review-queue-r8ux specs).
 *
 * What this tests:
 * - Page loads without JS errors
 * - Name + domain form elements are visible with seeded values
 * - "Save changes" button is disabled when form is pristine
 * - "Save changes" button enables after editing the name
 * - Domain-change warning appears when domain is modified (connection warning UX)
 * - Danger Zone is hidden by default (collapsed, aria-expanded=false)
 * - Danger Zone expands on click
 * - Typed-confirmation delete flow: button disabled until domain typed correctly
 * - Cancel resets the typed-confirmation flow
 * - Zero failed XHR requests on page load
 * - Unauthenticated access redirects to login
 */

import { execSync } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { expect, test } from '../fixtures/auth';

// ---------------------------------------------------------------------------
// Known environmental noise — not application-level errors
// Matches patterns from peer workflow specs in this suite.
// ---------------------------------------------------------------------------
const CONSOLE_NOISE = [
  '/api/lead-score',
  '/profile',
  'ERR_TOO_MANY_REDIRECTS',
  'favicon',
  'chrome-extension',
  'extension',
  'ResizeObserver loop',
  'Non-Error promise rejection',
];

const XHR_NOISE_URLS = [
  '/profile',
  '/api/lead-score',
  'favicon',
];

function isAppError(msg: string): boolean {
  return !CONSOLE_NOISE.some((n) => msg.includes(n));
}

function isNoiseRequest(url: string): boolean {
  return XHR_NOISE_URLS.some((n) => url.includes(n));
}

// ---------------------------------------------------------------------------
// public_id resolver (same pattern as pd-001-entry-verb and review-queue specs)
// ---------------------------------------------------------------------------
function runPhp(phpCode: string): string {
  const tmpFile = path.join('/tmp', `e2e_settings_general_${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 */ }
  }
}

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 public_id once before all tests in this describe block
// ---------------------------------------------------------------------------
let sitePublicId = '';

test.beforeAll(async ({ seedData }) => {
  sitePublicId = resolveSitePublicId(seedData.siteId);
});

// ---------------------------------------------------------------------------
// Happy-path and sad-path tests
// ---------------------------------------------------------------------------
test.describe('Site Settings — General (e0a0b5cb)', () => {
  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(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    const appErrors = errors.filter(isAppError);
    expect(appErrors, `Console errors found: ${appErrors.join(' | ')}`).toHaveLength(0);
  });

  test('shows name and domain fields with seeded values', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    const nameInput = page.getByLabel('Site name');
    const domainInput = page.getByLabel('Domain');

    await expect(nameInput).toBeVisible();
    await expect(domainInput).toBeVisible();

    const nameValue = await nameInput.inputValue();
    const domainValue = await domainInput.inputValue();
    expect(nameValue.length).toBeGreaterThan(0);
    expect(domainValue.length).toBeGreaterThan(0);
  });

  test('"Save changes" button is disabled when form is pristine', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    const saveButton = page.getByRole('button', { name: /save changes/i });
    await expect(saveButton).toBeVisible();
    await expect(saveButton).toBeDisabled();
  });

  test('"Save changes" button enables after editing the name', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    const nameInput = page.getByLabel('Site name');
    await nameInput.fill('Updated E2E Test Site');

    const saveButton = page.getByRole('button', { name: /save changes/i });
    await expect(saveButton).toBeEnabled();
  });

  test('domain field is visible and editable', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    const domainInput = page.getByLabel('Domain');
    const originalDomain = await domainInput.inputValue();

    await domainInput.fill('https://changed-domain-e2e.example.com');
    const saveButton = page.getByRole('button', { name: /save changes/i });
    await expect(saveButton).toBeEnabled();

    // Restore to avoid side effects
    await domainInput.fill(originalDomain);
  });

  test('Danger Zone section is collapsed by default', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    const dangerZoneToggle = page.getByRole('button', { name: /danger zone/i });
    await expect(dangerZoneToggle).toBeVisible();
    await expect(dangerZoneToggle).toHaveAttribute('aria-expanded', 'false');

    // Delete button inside danger zone is NOT visible while collapsed
    const deleteButton = page.getByRole('button', { name: /delete this site/i });
    await expect(deleteButton).not.toBeVisible();
  });

  test('Danger Zone expands on click and shows delete button', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    const dangerZoneToggle = page.getByRole('button', { name: /danger zone/i });
    await dangerZoneToggle.click();
    await expect(dangerZoneToggle).toHaveAttribute('aria-expanded', 'true');

    const deleteButton = page.getByRole('button', { name: /delete this site/i });
    await expect(deleteButton).toBeVisible();
  });

  test('typed-confirmation: final delete button disabled until domain typed correctly', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    // Open danger zone
    await page.getByRole('button', { name: /danger zone/i }).click();

    // Reveal confirmation input
    await page.getByRole('button', { name: /delete this site/i }).click();

    const confirmDeleteBtn = page.getByRole('button', { name: /delete site permanently/i });
    await expect(confirmDeleteBtn).toBeVisible();
    await expect(confirmDeleteBtn).toBeDisabled();

    // Wrong value keeps button disabled
    const confirmInput = page.getByLabel(/type.*to confirm/i);
    await confirmInput.fill('wrong-value');
    await expect(confirmDeleteBtn).toBeDisabled();
  });

  test('typed-confirmation: cancel resets the flow', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

    // Open danger zone → delete confirmation
    await page.getByRole('button', { name: /danger zone/i }).click();
    await page.getByRole('button', { name: /delete this site/i }).click();

    // Cancel should close confirmation and return to "Delete this site"
    const cancelButton = page.getByRole('button', { name: /cancel/i });
    await expect(cancelButton).toBeVisible();
    await cancelButton.click();

    await expect(page.getByRole('button', { name: /delete this site/i })).toBeVisible();
    await expect(page.getByRole('button', { name: /delete site permanently/i })).not.toBeVisible();
  });

  test('zero failed XHR requests on page load', async ({ page }) => {
    const failedRequests: string[] = [];
    page.on('response', (response) => {
      const url = response.url();
      const status = response.status();
      if (status >= 400 && !isNoiseRequest(url) && !url.includes('chrome-extension') && !url.includes('extension://')) {
        failedRequests.push(`${status} ${url}`);
      }
    });

    await page.goto(`/sites/${sitePublicId}/settings/general`, { waitUntil: 'networkidle' });

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

test.describe('Site Settings — General unauthenticated (e0a0b5cb)', () => {
  test('blocks unauthenticated access and redirects to login', async ({ browser }) => {
    const context = await browser.newContext({ storageState: { cookies: [], origins: [] } });
    const page = await context.newPage();

    await page.goto(`https://rankwiz.test/sites/${sitePublicId}/settings/general`);
    await expect(page).toHaveURL(/\/login/);

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