/**
 * Lexicon unit test — R8UX-011 / PD-001
 *
 * Enumerates the canonical run/queue nouns to prevent vocabulary drift.
 * Single authoritative list so a grep on "Recovery Run" can be validated
 * against these constants rather than scattered ad-hoc strings.
 *
 * PD-001: also asserts that every bulk-rewrite ENTRY CTA across CI/Recs/Freshness
 * resolves to the single canonical entry verb (ACTION_LABELS.bulkRewrite), and that
 * each surface's ScopeCostModal confirmLabel still matches its own scoped title.
 */
import { describe, it, expect } from 'vitest';

import { ACTION_LABELS, FEATURE_NAMES, MODAL_COPY, RUN_NOUNS } from './actionLexicon';

describe('actionLexicon — R8UX-011 run/queue noun registry', () => {
  it('RUN_NOUNS.manualRun resolves to "Recovery Run" — the manual batch journey', () => {
    expect(RUN_NOUNS.manualRun).toBe('Recovery Run');
  });

  it('RUN_NOUNS.manualRunPage resolves to "Recovery Runs" — batch-ai.index H1', () => {
    expect(RUN_NOUNS.manualRunPage).toBe('Recovery Runs');
  });

  it('RUN_NOUNS.autopilotPage resolves to "Autopilot History" — sites.recovery-runs.index', () => {
    expect(RUN_NOUNS.autopilotPage).toBe('Autopilot History');
  });

  it('RUN_NOUNS.heroHistoryLink resolves to "View past runs" — hero bottom link copy', () => {
    expect(RUN_NOUNS.heroHistoryLink).toBe('View past runs');
  });

  it('ACTION_LABELS.sendToRecovery still says "Send to Recovery Run" (Recovery Run journey noun)', () => {
    expect(ACTION_LABELS.sendToRecovery).toBe('Send to Recovery Run');
  });

  it('FEATURE_NAMES.recoveryRun still refers to the manual journey', () => {
    expect(FEATURE_NAMES.recoveryRun).toBe('Recovery Run');
  });

  it('RUN_NOUNS exports are string constants (not undefined)', () => {
    for (const [key, value] of Object.entries(RUN_NOUNS)) {
      expect(typeof value, `RUN_NOUNS.${key}`).toBe('string');
      expect(value.trim().length, `RUN_NOUNS.${key} must be non-empty`).toBeGreaterThan(0);
    }
  });
});

// PD-001 tests are LEXICON-CONTRACT tests only — they assert the value of
// ACTION_LABELS.bulkRewrite, not that each consumer component renders that string.
// Consumer render integration is out-of-scope here; these tests guard against
// someone renaming/retyping the constant value without noticing. A regression in
// a consumer's prop wiring would require a component render test in that page's
// own test file.
describe('actionLexicon — PD-001 canonical entry verb for bulk-rewrite surfaces', () => {
  const CANONICAL_ENTRY_VERB = 'Rewrite with AI';

  it('ACTION_LABELS.bulkRewrite is the canonical entry verb for all bulk-rewrite CTAs', () => {
    expect(ACTION_LABELS.bulkRewrite).toBe(CANONICAL_ENTRY_VERB);
  });

  it('ACTION_LABELS.sendToRecovery is distinct from bulkRewrite (entry verb ≠ modal confirm verb)', () => {
    expect(ACTION_LABELS.sendToRecovery).not.toBe(ACTION_LABELS.bulkRewrite);
  });

  it('Content Inventory bulk bar primary entry CTA resolves to canonical bulkRewrite label', () => {
    // CI bulk bar uses ACTION_LABELS.bulkRewrite (was sendToRecovery before PD-001).
    expect(ACTION_LABELS.bulkRewrite).toBe(CANONICAL_ENTRY_VERB);
  });

  it('Recommendations header primary entry CTA resolves to canonical bulkRewrite label', () => {
    // Recs header uses ACTION_LABELS.bulkRewrite (was inline "Generate N Drafts" before PD-001).
    expect(ACTION_LABELS.bulkRewrite).toBe(CANONICAL_ENTRY_VERB);
  });

  it('Recommendations BulkActionsBar entry CTA resolves to canonical bulkRewrite label', () => {
    // BulkActionsBar uses ACTION_LABELS.bulkRewrite (was inline "Generate N Drafts" before PD-001).
    expect(ACTION_LABELS.bulkRewrite).toBe(CANONICAL_ENTRY_VERB);
  });

  it('Freshness BulkActionBar entry CTA already resolves to canonical bulkRewrite label', () => {
    // Freshness was already correct — this assertion locks it in.
    expect(ACTION_LABELS.bulkRewrite).toBe(CANONICAL_ENTRY_VERB);
  });

  it('All three surfaces share the single canonical entry verb (no synonym drift)', () => {
    // Surfaces: CI (bulk bar), Recs (header + bulk bar), Freshness (bulk bar).
    // All must resolve to the same string — one concept, one verb.
    const ciEntryVerb = ACTION_LABELS.bulkRewrite;
    const recsEntryVerb = ACTION_LABELS.bulkRewrite;
    const freshnessEntryVerb = ACTION_LABELS.bulkRewrite;
    expect(ciEntryVerb).toBe(recsEntryVerb);
    expect(recsEntryVerb).toBe(freshnessEntryVerb);
    expect(ciEntryVerb).toBe(CANONICAL_ENTRY_VERB);
  });

  it('MODAL_COPY titles are surface-scoped (different from entry verb — intentional)', () => {
    // R11UX-101 guard: modal title !== entry CTA is expected.
    // Each modal title is scoped to its surface context and co-located with its confirmLabel.
    expect(MODAL_COPY.contentInventory.title).not.toBe(CANONICAL_ENTRY_VERB);
    expect(MODAL_COPY.freshness.title).not.toBe(CANONICAL_ENTRY_VERB);
    expect(MODAL_COPY.recommendations.title).not.toBe(CANONICAL_ENTRY_VERB);
    expect(MODAL_COPY.cannibalization.title).not.toBe(CANONICAL_ENTRY_VERB);
    expect(MODAL_COPY.topicClusters.title).not.toBe(CANONICAL_ENTRY_VERB);
  });

  it('MODAL_COPY confirmLabel matches title on each surface (R11UX-101 money-button guard)', () => {
    // R11UX-101: the paid-commit button verb must match the modal title.
    expect(MODAL_COPY.contentInventory.confirmLabel).toBe(MODAL_COPY.contentInventory.title);
    expect(MODAL_COPY.freshness.confirmLabel).toBe(MODAL_COPY.freshness.title);
    expect(MODAL_COPY.recommendations.confirmLabel).toBe(MODAL_COPY.recommendations.title);
    expect(MODAL_COPY.cannibalization.confirmLabel).toBe(MODAL_COPY.cannibalization.title);
    expect(MODAL_COPY.topicClusters.confirmLabel).toBe(MODAL_COPY.topicClusters.title);
  });
});
