import { chromium } from 'playwright';
import assert from 'node:assert/strict';

const appUrl = new URL(process.env.TIMMY_STAGING_URL || 'http://127.0.0.1:4173/');
const expectedTag = process.env.TIMMY_EXPECT_RELEASE_TAG || 'daily-test';
const expectedCommit = process.env.TIMMY_EXPECT_RELEASE_COMMIT || 'c'.repeat(40);
const username = process.env.TIMMY_STAGING_USER || '';
const password = process.env.TIMMY_STAGING_PASSWORD || '';
const loopback = ['127.0.0.1', 'localhost', '::1'].includes(appUrl.hostname);
if (!loopback && (!username || !password)) throw new Error('Live staging smoke requires TIMMY_STAGING_USER and TIMMY_STAGING_PASSWORD.');
if (!/^[0-9a-f]{40}$/.test(expectedCommit)) throw new Error('TIMMY_EXPECT_RELEASE_COMMIT must be a full lowercase commit.');

const browser = await chromium.launch({ headless: true });
try {
  const context = await browser.newContext({
    viewport: { width: 390, height: 844 },
    deviceScaleFactor: 2,
    serviceWorkers: 'block',
    acceptDownloads: true,
    ...(username && password ? { httpCredentials: { username, password } } : {}),
  });
  const page = await context.newPage();
  const browserErrors = [];
  const secretFindings = [];
  let agentChatRequests = 0;
  page.on('console', message => { if (message.type() === 'error') browserErrors.push(message.text()); });
  page.on('pageerror', error => browserErrors.push(error.message));
  page.on('request', request => { if (new URL(request.url()).pathname.endsWith('/api/agent/chat')) agentChatRequests += 1; });
  page.on('response', async response => {
    const url = new URL(response.url());
    if (!url.pathname.includes('/api/')) return;
    for (const name of Object.keys(response.headers())) {
      if (/authorization|set-cookie|x-api-key/i.test(name)) secretFindings.push(`sensitive response header ${name}`);
    }
    try {
      const type = response.headers()['content-type'] || '';
      if (/json|text/.test(type)) {
        const body = (await response.text()).slice(0, 65_537);
        if (body.length > 65_536) secretFindings.push('oversized API response');
        if (/"(?:password|token|cookie|session|api[_-]?key|credential|environment|processEnv)"\s*:/i.test(body)) secretFindings.push(`secret-bearing response ${url.pathname}`);
      }
    } catch {}
  });

  const navigation = await page.goto(appUrl.toString(), { waitUntil: 'networkidle' });
  assert.equal(navigation?.status(), 200, 'edge authentication and staging navigation must succeed');
  await page.evaluate(() => localStorage.clear());
  await page.reload({ waitUntil: 'networkidle' });

  const healthUrl = new URL(`${appUrl.pathname.replace(/\/$/, '')}/api/healthz`, appUrl);
  const health = await page.evaluate(async url => {
    const response = await fetch(url, { headers: { accept: 'application/json' } });
    return { status: response.status, body: await response.json() };
  }, healthUrl.toString());
  assert.equal(health.status, 200);
  assert.equal(health.body.ok, true);
  assert.equal(health.body.release, expectedTag);
  assert.equal(health.body.commit, expectedCommit);
  assert.equal(health.body.agentEnabled, false, 'Phase 1 staging must keep Hermes off');

  assert.match(await page.locator('.staging-label').innerText(), new RegExp(`Staging · ${expectedTag.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')} · ${expectedCommit.slice(0, 12)}`));
  assert.equal(await page.locator('main .btn-primary:visible').count(), 1, 'exactly one dominant photo action');
  assert.equal(await page.locator('[data-log]:visible').count(), 1, 'manual fallback remains visible');
  assert.equal(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), true, 'home must not overflow');

  await page.locator('[data-log]:visible').click();
  await page.locator('[data-type="4"]').click();
  await page.locator('#next').click();
  await page.locator('#note').fill('synthetic staging smoke');
  await page.locator('#next').click();
  await page.locator('#save').click();

  await page.getByRole('button', { name: 'Journal', exact: true }).click();
  assert.match(await page.locator('main').innerText(), /synthetic staging smoke/);
  assert.equal(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), true, 'journal must not overflow');

  await page.getByRole('button', { name: 'Timmy', exact: true }).click();
  await page.locator('#chat-message').fill('I barfed');
  await page.locator('#send-chat').click();
  await page.waitForSelector('.bubble.timmy >> text=Pause and get medical help');
  assert.equal(agentChatRequests, 0, 'urgent phrase must be intercepted before Hermes');

  await page.getByRole('button', { name: 'Journal', exact: true }).click();
  await page.locator('[data-view="privacy"]').click();
  const downloadPromise = page.waitForEvent('download');
  await page.locator('#export').click();
  const download = await downloadPromise;
  assert.equal(download.suggestedFilename(), 'timmy-ledger.json');
  assert.equal(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), true, 'privacy screen must not overflow');

  await page.waitForTimeout(100);
  assert.deepEqual(secretFindings, []);
  assert.deepEqual(browserErrors, []);
  await context.close();
  console.log(`PASS staging smoke ${expectedTag} ${expectedCommit.slice(0, 12)} at ${appUrl}`);
} finally {
  await browser.close();
}
