/**
 * Property-Based Tests: Config Wizard Frontend Build Skip Logic
 *
 * Feature: config-wizard
 *
 * Tests the shouldSkipFrontendBuild function from `configure.js`.
 *
 * Validates: Requirements 14.4, 14.5
 */

const fc = require('fast-check');
const { shouldSkipFrontendBuild } = require('../../configure.js');

// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────

/** Generate a REACT_APP_* key name */
const reactAppKeyArb = fc.stringMatching(/^REACT_APP_[A-Z][A-Z0-9_]{0,15}$/)
  .filter(k => k.length > 10);

/** Generate a non-empty env value */
const envValueArb = fc.string({ minLength: 1, maxLength: 50 })
  .filter(s => s.trim().length > 0 && !s.includes('\n'));

// ─────────────────────────────────────────────────────────────────────────────
// Property 19: Frontend build skip determination
// ─────────────────────────────────────────────────────────────────────────────

describe('Property 19: Frontend build skip determination', () => {
  /**
   * **Validates: Requirements 14.4, 14.5**
   *
   * shouldSkipFrontendBuild returns true iff all REACT_APP_* keys have identical
   * values in old and new maps and old map is non-null.
   */

  test('when old map is null, always returns false', () => {
    fc.assert(
      fc.property(
        fc.array(fc.tuple(reactAppKeyArb, envValueArb), { minLength: 1, maxLength: 5 }),
        (entries) => {
          const newMap = new Map(entries);
          return shouldSkipFrontendBuild(null, newMap) === false;
        }
      ),
      { numRuns: 100 }
    );
  });

  test('when old and new have identical REACT_APP_* values, returns true', () => {
    fc.assert(
      fc.property(
        fc.array(fc.tuple(reactAppKeyArb, envValueArb), { minLength: 1, maxLength: 5 }),
        (entries) => {
          // Deduplicate keys by using a Map
          const deduped = [...new Map(entries).entries()];
          const oldMap = new Map(deduped);
          const newMap = new Map(deduped);
          return shouldSkipFrontendBuild(oldMap, newMap) === true;
        }
      ),
      { numRuns: 100 }
    );
  });

  test('when any REACT_APP_* value differs, returns false', () => {
    fc.assert(
      fc.property(
        fc.array(fc.tuple(reactAppKeyArb, envValueArb), { minLength: 1, maxLength: 5 }),
        envValueArb,
        (entries, differentValue) => {
          // Deduplicate keys
          const deduped = [...new Map(entries).entries()];
          if (deduped.length === 0) return true; // skip trivial case

          const oldMap = new Map(deduped);
          const newMap = new Map(deduped);

          // Change one value in the new map to be different
          const keyToChange = deduped[0][0];
          const originalValue = deduped[0][1];
          // Ensure the new value is actually different
          const newValue = differentValue === originalValue
            ? differentValue + '_changed'
            : differentValue;
          newMap.set(keyToChange, newValue);

          return shouldSkipFrontendBuild(oldMap, newMap) === false;
        }
      ),
      { numRuns: 100 }
    );
  });

  test('when new map has additional REACT_APP_* keys not in old, returns false', () => {
    fc.assert(
      fc.property(
        fc.array(fc.tuple(reactAppKeyArb, envValueArb), { minLength: 1, maxLength: 3 }),
        reactAppKeyArb,
        envValueArb,
        (entries, extraKey, extraValue) => {
          // Deduplicate keys
          const deduped = [...new Map(entries).entries()];
          const oldMap = new Map(deduped);
          const newMap = new Map(deduped);

          // Add an extra key to new that doesn't exist in old
          // Ensure the extra key is not already in the map
          const uniqueExtraKey = deduped.some(([k]) => k === extraKey)
            ? extraKey + '_EXTRA'
            : extraKey;
          newMap.set(uniqueExtraKey, extraValue);

          return shouldSkipFrontendBuild(oldMap, newMap) === false;
        }
      ),
      { numRuns: 100 }
    );
  });
});
