'use strict';

/**
 * DC-058 share preview page static-analysis test.
 *
 * Validates the static contract of status/share/index.html:
 *   1. parses cleanly (no malformed HTML/CSS/JS)
 *   2. exposes the expected public endpoints (preview fetch + subscribe POST)
 *   3. does NOT call the redeem-tailscale endpoint from the client (the
 *      redemption flow lives on Caddy, not the browser — see the
 *      server-side handler at routes/share.js)
 *   4. extracts the share token from the URL path
 *   5. shows the right CTA copy for public vs Tailscale shares
 *
 * This is a regression guard for the "fake Tailscale redemption" bug codex
 * flagged in the first review pass: an earlier version of the page POSTed
 * a random deviceId to /redeem-tailscale, which silently consumed the
 * one-shot share and broke the legitimate Tailscale join.
 *
 * Source path resolution: the standard location is `status/share/index.html`.
 * The judge-artifact.sh wrapper sometimes copies the file into a flat
 * worktree with a numeric prefix (e.g. `3_index.html`), so we fall back
 * to a directory scan.
 */

const fs = require('fs');
const path = require('path');
const vm = require('vm');
const test = require('node:test');
const assert = require('node:assert/strict');

function findTarget(name) {
  const candidates = [
    path.join(__dirname, '..', 'share', 'index.html'),
    path.join(__dirname, 'share', 'index.html'),
    path.join(__dirname, 'index.html'),
  ];
  for (const p of candidates) {
    try { if (fs.statSync(p).isFile()) return p; } catch (_) { /* keep looking */ }
  }
  const dir = __dirname;
  let entries = [];
  try { entries = fs.readdirSync(dir); } catch (_) { return null; }
  const match = entries.find(e => e === name || e.endsWith('_' + name) || e.endsWith('-' + name));
  return match ? path.join(dir, match) : null;
}

const SHARE_PAGE_PATH = findTarget('index.html');
if (!SHARE_PAGE_PATH) {
  throw new Error(
    'Cannot find share/index.html. Searched standard paths + directory scan of ' +
    __dirname + '. If running under judge-artifact.sh, ensure the wrapper ' +
    'passed the file via --files.'
  );
}

let pageHtml;
let pageSource;
function loadPage() {
  pageHtml = fs.readFileSync(SHARE_PAGE_PATH, 'utf8');
  const scriptMatch = pageHtml.match(/<script>([\s\S]*?)<\/script>/);
  pageSource = scriptMatch ? scriptMatch[1] : '';
  return { html: pageHtml, source: pageSource };
}

test('share preview page exists and is non-empty', () => {
  const { html } = loadPage();
  assert.ok(html.length > 1000, 'expected non-trivial HTML');
  assert.match(html, /<title>DashCaddy Share<\/title>/);
});

test('share preview page inline JS parses without syntax errors', () => {
  const { source } = loadPage();
  assert.doesNotThrow(() => new vm.Script(source, { filename: 'share-preview.js' }));
});

test('share preview page calls the preview endpoint relative to the token', () => {
  const { source } = loadPage();
  assert.match(source, /\/api\/v1\/share\/.*\/preview/,
    'page must fetch the share preview via GET /api/v1/share/<token>/preview');
  // CRITICAL: the redemption endpoint must NEVER be called from the client.
  // The Tailscale join is a server-side flow (Caddy forward_auth checks the
  // share store on each request — the link itself is the credential).
  assert.doesNotMatch(source, /\/redeem-tailscale/,
    'page must NOT call /redeem-tailscale — redemption is server-side');
});

test('share preview page calls the subscribe endpoint, not the issue endpoint', () => {
  const { source } = loadPage();
  assert.match(source, /\/api\/v1\/share\/.*\/subscribe/,
    'page must allow subscribing via POST /api/v1/share/<token>/subscribe');
});

test('share preview page extracts the token from the URL path', () => {
  const { source } = loadPage();
  assert.match(source, /window\.location\.pathname/,
    'page must read the share token from the URL path');
  assert.match(source, /split\(['"]\/['"]\)/,
    'page must split the path on "/" to extract the token');
});

test('share preview page has both public and Tailscale CTAs', () => {
  const { html, source } = loadPage();
  assert.match(html, /id="cta-public"/);
  assert.match(html, /id="cta-tailscale"/);
  assert.match(html, /tailscale\.com\/download/);
  assert.match(source, /data\.kind === 'tailscale'/,
    'script must branch the CTA on the kind= field returned by the API');
});

test('share preview page full source passes new Function() syntax check', () => {
  const { source } = loadPage();
  assert.doesNotThrow(() => new Function(source));
});

test('share preview page does NOT mention a fake / pending deviceId', () => {
  // Regression guard for the original bug: the page used to fabricate a
  // random "pending-XXXXXX" deviceId and POST it to /redeem-tailscale,
  // which silently consumed the one-shot share. The page now has no
  // client-side redemption path.
  const { source } = loadPage();
  assert.doesNotMatch(source, /pending-/, 'no placeholder deviceId fabrication');
  assert.doesNotMatch(source, /Math\.random/, 'no random fallback that used to invent deviceIds');
});
