/**
 * Property-Based Tests: Config Wizard Parsing Functions
 *
 * Feature: config-wizard
 *
 * Tests the parsing and derived-default functions from `configure.js`.
 *
 * Validates: Requirements 4.1, 4.2, 4.6
 */

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

// --- Property 5: Shell variable default resolution ---
describe('Property 5: Shell variable default resolution', () => {
  /**
   * **Validates: Requirements 4.1**
   *
   * For any string containing the pattern ${VARNAME:-defaultvalue},
   * resolveShellDefault extracts and returns defaultvalue.
   * For any string not containing that pattern, it returns the original
   * string (with surrounding quotes stripped).
   */
  test('resolveShellDefault extracts default from ${VAR:-default} pattern', () => {
    // Generate valid variable names and default values
    const varNameArb = fc.stringMatching(/^[A-Z][A-Z0-9_]{0,19}$/);
    const defaultValueArb = fc.string({ minLength: 1, maxLength: 50 })
      .filter(s => !s.includes('}'));

    fc.assert(
      fc.property(varNameArb, defaultValueArb, (varName, defaultValue) => {
        const input = `\${${varName}:-${defaultValue}}`;
        const result = resolveShellDefault(input);
        return result === defaultValue;
      }),
      { numRuns: 100 }
    );
  });

  test('resolveShellDefault returns original string (quotes stripped) for non-matching patterns', () => {
    // Generate strings that do NOT contain the ${VAR:-default} pattern
    // and do not have leading/trailing quotes (which would be stripped)
    const plainStringArb = fc.string({ minLength: 1, maxLength: 50 })
      .filter(s =>
        !/\$\{[^:}]+:-[^}]+\}/.test(s) &&
        !s.startsWith("'") && !s.startsWith('"') &&
        !s.endsWith("'") && !s.endsWith('"')
      );

    fc.assert(
      fc.property(plainStringArb, (input) => {
        const result = resolveShellDefault(input);
        return result === input;
      }),
      { numRuns: 100 }
    );
  });

  test('resolveShellDefault strips surrounding quotes from non-matching strings', () => {
    const innerStringArb = fc.string({ minLength: 1, maxLength: 30 })
      .filter(s => !s.includes("'") && !s.includes('"') && !/\$\{[^:}]+:-[^}]+\}/.test(s));

    fc.assert(
      fc.property(
        innerStringArb,
        fc.constantFrom("'", '"'),
        (inner, quote) => {
          const input = `${quote}${inner}${quote}`;
          const result = resolveShellDefault(input);
          return result === inner;
        }
      ),
      { numRuns: 100 }
    );
  });
});

// --- Property 6: DATABASE_URL construction ---
describe('Property 6: DATABASE_URL construction', () => {
  /**
   * **Validates: Requirements 4.2**
   *
   * For any valid credentials tuple (user, password, port in [1,65535], database),
   * the constructed URL equals postgresql://{user}:{password}@localhost:{port}/{database}.
   */
  test('computeDerivedDefaults constructs correct DATABASE_URL from compose result', () => {
    const credentialArb = fc.record({
      user: fc.string({ minLength: 1, maxLength: 30 }).filter(s => s.trim().length > 0 && !s.includes(':') && !s.includes('@') && !s.includes('/')),
      password: fc.string({ minLength: 1, maxLength: 30 }).filter(s => s.trim().length > 0 && !s.includes('@') && !s.includes('/')),
      port: fc.integer({ min: 1, max: 65535 }).map(String),
      database: fc.string({ minLength: 1, maxLength: 30 }).filter(s => s.trim().length > 0 && !s.includes('/') && !s.includes('@') && !s.includes(':'))
    });

    fc.assert(
      fc.property(credentialArb, (creds) => {
        const result = computeDerivedDefaults('3001', 'localhost', creds);
        const expected = `postgresql://${creds.user}:${creds.password}@localhost:${creds.port}/${creds.database}`;
        return result.DATABASE_URL === expected;
      }),
      { numRuns: 100 }
    );
  });

  test('computeDerivedDefaults sets databaseUrlSource to compose when compose result provided', () => {
    const credentialArb = fc.record({
      user: fc.string({ minLength: 1, maxLength: 20 }).filter(s => s.trim().length > 0),
      password: fc.string({ minLength: 1, maxLength: 20 }).filter(s => s.trim().length > 0),
      port: fc.integer({ min: 1, max: 65535 }).map(String),
      database: fc.string({ minLength: 1, maxLength: 20 }).filter(s => s.trim().length > 0)
    });

    fc.assert(
      fc.property(credentialArb, (creds) => {
        const result = computeDerivedDefaults('3001', 'localhost', creds);
        return result.databaseUrlSource === 'compose';
      }),
      { numRuns: 100 }
    );
  });
});

// --- Property 7: Derived URL defaults from PORT and API_HOST ---
describe('Property 7: Derived URL defaults from PORT and API_HOST', () => {
  /**
   * **Validates: Requirements 4.6**
   *
   * For any valid port P and host H, REACT_APP_API_BASE equals
   * http://{H}:{P}/api, REACT_APP_API_HOST equals http://{H}:{P},
   * CORS_ORIGINS equals http://localhost:3000.
   */
  test('derived defaults produce correct REACT_APP_API_BASE, REACT_APP_API_HOST, and CORS_ORIGINS', () => {
    const portArb = fc.integer({ min: 1, max: 65535 }).map(String);
    const hostArb = fc.string({ minLength: 1, maxLength: 50 })
      .filter(s => s.trim().length > 0 && !s.includes(':') && !s.includes('/'));

    fc.assert(
      fc.property(portArb, hostArb, (port, host) => {
        const result = computeDerivedDefaults(port, host, null);

        const apiBaseCorrect = result.REACT_APP_API_BASE === `http://${host}:${port}/api`;
        const apiHostCorrect = result.REACT_APP_API_HOST === `http://${host}:${port}`;
        const corsCorrect = result.CORS_ORIGINS === 'http://localhost:3000';

        return apiBaseCorrect && apiHostCorrect && corsCorrect;
      }),
      { numRuns: 100 }
    );
  });

  test('CORS_ORIGINS is always http://localhost:3000 regardless of port and host', () => {
    const portArb = fc.integer({ min: 1, max: 65535 }).map(String);
    const hostArb = fc.string({ minLength: 1, maxLength: 30 })
      .filter(s => s.trim().length > 0);

    fc.assert(
      fc.property(portArb, hostArb, (port, host) => {
        const result = computeDerivedDefaults(port, host, null);
        return result.CORS_ORIGINS === 'http://localhost:3000';
      }),
      { numRuns: 100 }
    );
  });

  test('when composeResult is null, databaseUrlSource is fallback', () => {
    const portArb = fc.integer({ min: 1, max: 65535 }).map(String);
    const hostArb = fc.constantFrom('localhost', '0.0.0.0', '192.168.1.1');

    fc.assert(
      fc.property(portArb, hostArb, (port, host) => {
        const result = computeDerivedDefaults(port, host, null);
        return result.databaseUrlSource === 'fallback';
      }),
      { numRuns: 100 }
    );
  });
});
