/**
 * Workflow spec: ROI Dashboard — "Download proof PDF" button (session d6834d9b)
 *
 * Covers the new "Download proof PDF" button added in:
 *   - resources/js/Pages/Roi/Dashboard.tsx (ROI-007)
 *   - app/Http/Controllers/RoiExportController::proofPdf()
 *
 * Golden path:
 *   1. Navigate to ROI dashboard with ROI data present (hasData=true)
 *   2. "Download proof PDF" button is visible
 *   3. The button href points to the sites.roi.proof-pdf route
 *   4. GET to that route returns application/pdf with a ULID-based filename
 *   5. No console errors on the page
 *
 * Regression check:
 *   - "Export CSV" button still present alongside the PDF button
 *
 * Sad paths:
 *   - Button is absent on the empty state (hasData=false)
 *   - Unauthenticated request to the PDF endpoint redirects to /login
 *
 * Background noise filter (APP_URL mismatch with test baseURL):
 *   /api/lead-score/pql-signal — 419 CSRF
 *   ERR_TOO_MANY_REDIRECTS    — polling XHRs when APP_URL is HTTPS
 */

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

// ---------------------------------------------------------------------------
// PHP execution helpers (same pattern as roi-dashboard-e5r6r7r8-02ac0323.spec.ts)
// ---------------------------------------------------------------------------

function runPhp(phpCode: string): string {
  const tmpFile = path.join('/tmp', `e2e_proof_pdf_${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 */ }
  }
}

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;
}

function createRoiSnapshot(siteId: number): void {
  runPhp(`
    $site = \\App\\Models\\Site::find(${siteId});
    $run = \\App\\Models\\AnalysisRun::where('site_id', $site->id)->first();
    if (!$run) { echo 'NO_RUN'; return; }
    $rec = \\App\\Models\\Recommendation::where('analysis_run_id', $run->id)->first();
    if (!$rec) { echo 'NO_REC'; return; }
    $existing = \\App\\Models\\RecommendationRoiSnapshot::where('recommendation_id', $rec->id)->first();
    if ($existing) { echo 'EXISTS'; return; }
    $rec->lifecycle_status = \\App\\Enums\\LifecycleStatus::Applied;
    $rec->save();
    \\App\\Models\\RecommendationRoiSnapshot::factory()->create([
      'recommendation_id' => $rec->id,
      'baseline_date' => now()->subDays(30),
      'baseline_clicks' => 100,
      'current_clicks' => 150,
      'clicks_delta' => 50,
      'clicks_delta_pct' => 50.0,
      'days_tracked' => 30,
      'is_significant' => true,
    ]);
    echo 'CREATED';
  `);
}

function cleanupRoiSnapshots(siteId: number): void {
  runPhp(`
    $site = \\App\\Models\\Site::find(${siteId});
    $run = \\App\\Models\\AnalysisRun::where('site_id', $site->id)->first();
    if ($run) {
      $recIds = \\App\\Models\\Recommendation::where('analysis_run_id', $run->id)->pluck('id');
      \\App\\Models\\RecommendationRoiSnapshot::whereIn('recommendation_id', $recIds)->delete();
    }
    echo 'CLEANUP_DONE';
  `);
}

// ---------------------------------------------------------------------------
// Known background noise
// ---------------------------------------------------------------------------
const KNOWN_NOISE = [
  '/api/lead-score/pql-signal',
  'ERR_TOO_MANY_REDIRECTS',
  '/profile',
];

// ---------------------------------------------------------------------------
// Resolved IDs (set once in beforeAll)
// ---------------------------------------------------------------------------
let sitePublicId = '';
let siteId = 0;

test.describe.configure({ mode: 'serial' });

test.describe('ROI Dashboard — Download proof PDF button (d6834d9b)', () => {
  test.beforeAll(async () => {
    const seedDataPath = path.join(process.cwd(), 'tests/e2e/.seed-data.json');
    const seedData = JSON.parse(fs.readFileSync(seedDataPath, 'utf8')) as { siteId: number };
    siteId = seedData.siteId;
    sitePublicId = resolveSitePublicId(siteId);
    console.log(`[ROI-PDF] site public_id: ${sitePublicId} (integer: ${siteId})`);
    // Ensure ROI snapshots exist so hasData=true
    createRoiSnapshot(siteId);
  });

  test.afterAll(async () => {
    cleanupRoiSnapshots(siteId);
  });

  // ── 1. Button visibility ──────────────────────────────────────────────────
  test('ROI-007: "Download proof PDF" button is visible when hasData is true', 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}/roi`, { waitUntil: 'domcontentloaded' });

    const pdfButton = page.getByRole('link', { name: /download proof pdf/i });
    await expect(pdfButton).toBeVisible();

    // Zero uncaught console errors
    const appErrors = errors.filter(
      (e) =>
        !e.includes('extension') &&
        !e.includes('chrome-extension') &&
        !KNOWN_NOISE.some((n) => e.includes(n)),
    );
    expect(appErrors, `Console errors: ${appErrors.join(', ')}`).toHaveLength(0);
  });

  // ── 2. Button href points to the correct route ────────────────────────────
  test('ROI-007: proof PDF button href contains the sites.roi.proof-pdf path', async ({ page }) => {
    await page.goto(`/sites/${sitePublicId}/roi`, { waitUntil: 'domcontentloaded' });

    const pdfButton = page.getByRole('link', { name: /download proof pdf/i });
    await expect(pdfButton).toBeVisible();

    const href = await pdfButton.getAttribute('href');
    expect(href).toBeTruthy();
    // Route resolves to /sites/{public_id}/roi/proof-pdf
    expect(href).toContain(`/sites/${sitePublicId}/roi/proof-pdf`);
  });

  // ── 3. Endpoint returns application/pdf ──────────────────────────────────
  test('ROI-007: GET sites.roi.proof-pdf returns application/pdf with ULID filename', async ({
    page,
  }) => {
    await page.goto(`/sites/${sitePublicId}/roi`, { waitUntil: 'domcontentloaded' });

    // Build the exact URL from the button href to avoid hardcoding
    const pdfButton = page.getByRole('link', { name: /download proof pdf/i });
    const href = (await pdfButton.getAttribute('href')) ?? '';
    expect(href).toBeTruthy();

    // Issue a same-session GET (authenticated) via fetch through the page context
    const response = await page.evaluate(async (url: string) => {
      const res = await fetch(url, { method: 'GET', redirect: 'follow' });
      return {
        status: res.status,
        contentType: res.headers.get('content-type') ?? '',
        contentDisposition: res.headers.get('content-disposition') ?? '',
      };
    }, href);

    expect(response.status, `Expected 200, got ${response.status}`).toBe(200);
    expect(
      response.contentType,
      `Expected application/pdf, got "${response.contentType}"`,
    ).toContain('application/pdf');

    // Filename must be attachment; filename="roi-proof-<ulid>-<date>.pdf"
    // ULID is 26 chars of [0-9A-Z], date is YYYY-MM-DD
    expect(
      response.contentDisposition,
      `Content-Disposition was: "${response.contentDisposition}"`,
    ).toMatch(/attachment;\s*filename="roi-proof-[A-Z0-9]{26}-\d{4}-\d{2}-\d{2}\.pdf"/i);
  });

  // ── 4. Regression: Export CSV button still present ────────────────────────
  test('Regression: "Export CSV" button is still visible alongside the PDF button', async ({
    page,
  }) => {
    await page.goto(`/sites/${sitePublicId}/roi`, { waitUntil: 'domcontentloaded' });

    // Both buttons must be visible simultaneously (co-rendered in header actions)
    await expect(page.getByRole('link', { name: /download proof pdf/i })).toBeVisible();
    await expect(page.getByRole('link', { name: /export csv/i })).toBeVisible();
  });

  // ── 5. No failed XHR on populated dashboard ───────────────────────────────
  test('Populated ROI dashboard produces no failed XHR requests', async ({ page }) => {
    const failedRequests: string[] = [];
    page.on('requestfailed', (req) => {
      const url = req.url();
      if (!KNOWN_NOISE.some((n) => url.includes(n))) {
        failedRequests.push(`${req.method()} ${url} — ${req.failure()?.errorText ?? 'unknown'}`);
      }
    });

    await page.goto(`/sites/${sitePublicId}/roi`, { waitUntil: 'domcontentloaded' });

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

  // ── 6. Sad path: button absent on empty state (hasData=false) ────────────
  test.describe('Empty state — button absent when no ROI data', () => {
    test.beforeAll(async () => {
      cleanupRoiSnapshots(siteId);
    });

    test.afterAll(async () => {
      // Restore snapshot so later specs still have data if they need it
      createRoiSnapshot(siteId);
    });

    test('ROI-007: "Download proof PDF" button is NOT rendered on empty state', async ({
      page,
    }) => {
      await page.goto(`/sites/${sitePublicId}/roi`, { waitUntil: 'domcontentloaded' });

      // Empty state (hasData=false) must NOT show the PDF download button
      await expect(
        page.getByRole('link', { name: /download proof pdf/i }),
      ).not.toBeAttached();
    });

    test('ROI-007: "Export CSV" button is NOT rendered on empty state', async ({ page }) => {
      await page.goto(`/sites/${sitePublicId}/roi`, { waitUntil: 'domcontentloaded' });

      // Both action buttons are conditional on hasData=true
      await expect(
        page.getByRole('link', { name: /export csv/i }),
      ).not.toBeAttached();
    });
  });

  // ── 7. Sad path: unauthenticated request blocked ──────────────────────────
  test('Unauthenticated GET to proof-pdf endpoint redirects to /login', async ({ browser }) => {
    const context = await browser.newContext({ storageState: { cookies: [], origins: [] } });
    const page = await context.newPage();

    await page.goto(`/sites/${sitePublicId}/roi/proof-pdf`);
    await expect(page).toHaveURL(/\/login/);

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