/**
 * DC-057 pricing-page catalog consistency test.
 *
 * The pricing page at status/pricing/index.html hard-codes the 4 product
 * IDs, prices, and labels. This test asserts that those hard-coded values
 * exactly match the catalog in src/billing/catalog.js — preventing drift
 * between the two sources.
 *
 * If a new tier is added to the catalog, this test will fail until the
 * pricing page is updated. If the pricing page is updated, the catalog
 * must change in lockstep (or this test fails the other way).
 */

const fs = require('fs');
const path = require('path');
const catalog = require('../../src/billing/catalog');

const PRICING_PAGE_PATH = path.join(__dirname, '..', '..', '..', 'status', 'pricing', 'index.html');

function extractTiersFromPage(html) {
  // Extract each `<div class="tier pro" data-product-id="...">` block, then
  // pull out the dollar amount in the `<div class="price">` element and
  // the durationDays from the "N-day Pro license" string. The regex is
  // anchored on the tier-class open + the matching buy-btn close so we
  // capture the full body of each tier card regardless of how many inner
  // divs it has.
  const tierRe = /<div class="tier pro" data-product-id="([^"]+)">([\s\S]*?)<button[^>]*class="buy-btn"[^>]*>\s*Buy/g;
  const tierBlocks = [...html.matchAll(tierRe)];
  return tierBlocks.map(([, productId, body]) => {
    const priceMatch = body.match(/<div class="price">\$(\d+)<\/div>/);
    const durMatch = body.match(/(\d+)-day Pro license/);
    return {
      productId,
      priceDollars: priceMatch ? parseInt(priceMatch[1], 10) : null,
      durationDays: durMatch ? parseInt(durMatch[1], 10) : null,
    };
  });
}

/**
 * Extract the HTML body for one specific tier (from open div through the
 * buy-btn). Used by per-tier assertions that must NOT bleed across cards.
 */
function extractTierBody(html, productId) {
  const re = new RegExp(
    `<div class="tier pro" data-product-id="${productId}">([\\s\\S]*?)<button[^>]*class="buy-btn"[^>]*>\\s*Buy`,
    'i'
  );
  const m = html.match(re);
  return m ? m[1] : null;
}

describe('pricing page <-> catalog consistency (DC-057)', () => {
  let html;
  let pageTiers;

  beforeAll(() => {
    html = fs.readFileSync(PRICING_PAGE_PATH, 'utf8');
    pageTiers = extractTiersFromPage(html);
  });

  test('pricing page exists and is readable', () => {
    expect(html.length).toBeGreaterThan(1000);
    expect(pageTiers.length).toBeGreaterThan(0);
  });

  test('every catalog product is rendered on the pricing page', () => {
    const catalogIds = catalog.PRODUCTS.map((p) => p.id).sort();
    const pageIds = pageTiers.map((t) => t.productId).sort();
    expect(pageIds).toEqual(catalogIds);
  });

  test('every pricing-page productId appears in the catalog', () => {
    for (const tier of pageTiers) {
      const product = catalog.getProduct(tier.productId);
      expect(product).not.toBeNull();
    }
  });

  test('pricing-page dollar amounts match catalog amountCents', () => {
    for (const tier of pageTiers) {
      const product = catalog.getProduct(tier.productId);
      const expectedDollars = product.amountCents / 100;
      expect(tier.priceDollars).toBe(expectedDollars);
    }
  });

  test('pricing-page duration strings match catalog durationDays', () => {
    for (const tier of pageTiers) {
      const product = catalog.getProduct(tier.productId);
      expect(tier.durationDays).toBe(product.durationDays);
    }
  });

  test('catalog and pricing page agree on price label (scoped per tier card)', () => {
    // Per-tier priceLabel assertion: each tier card must include its
    // own catalog.priceLabel. A swap or misplaced label fails immediately
    // because the assertion checks the tier's own HTML body, not the page.
    for (const tier of pageTiers) {
      const product = catalog.getProduct(tier.productId);
      const body = extractTierBody(html, tier.productId);
      expect(body).not.toBeNull();
      // The priceLabel appears in the price div of THIS tier only,
      // immediately followed by the closing </div> + the duration block.
      const labelRegex = new RegExp(`<div class="price">\\s*\\${product.priceLabel}\\s*</div>\\s*<div class="duration"`);
      expect(body).toMatch(labelRegex);
    }
  });

  test('pricing page does not include the monthly/annual subscription toggle (one-time only)', () => {
    // DC-057 acceptance: locked spec is ONE-TIME 30/90/180/365-day licenses
    // at $20/$50/$70/$99. The old monthly/annual subscription toggle
    // would contradict the spec.
    expect(html).not.toMatch(/period-monthly|period-annual/);
    expect(html).not.toMatch(/Subscribe to Pro/);
  });

  test('pricing page references the success-page endpoint', () => {
    // The success URL is constructed server-side in stripe-client.js
    // (${origin}/billing/success?session_id=...). The pricing page itself
    // doesn't need to embed it — but the FOOTER must reference it so the
    // customer knows where to go after Stripe redirects.
    expect(html.toLowerCase()).toContain('after payment');
    expect(html).toContain('/admin/license');
    expect(html).toContain('/api/v1/billing/checkout');
  });

  test('success page (status/billing/success.html) exists and references the lookup endpoint', () => {
    const successPath = path.join(__dirname, '..', '..', '..', 'status', 'billing', 'success.html');
    const successHtml = fs.readFileSync(successPath, 'utf8');
    expect(successHtml).toContain('/api/v1/billing/lookup/');
    expect(successHtml.length).toBeGreaterThan(1000);
  });
});
