'use strict';

require('../common');
const fixtures = require('../common/fixtures.js');
const tmpdir = require('../common/tmpdir');
const assert = require('node:assert');
const fs = require('node:fs');
const { spawnSync } = require('node:child_process');
const { describe, it } = require('node:test');
const path = require('node:path');

const fixtureDir = fixtures.path('test-runner', 'flag-propagation');
const runner = path.join(fixtureDir, 'runner.mjs');

describe('test runner flag propagation', () => {
  describe('via command line', () => {
    const flagPropagationTests = [
      ['--experimental-config-file=node.config.json', '', '', '--experimental-config-file',
       'should not propagate --experimental-config-file to child tests'],
      ['--experimental-default-config-file', '', '', '--experimental-config-file',
       'should not propagate --experimental-default-config-file to child tests'],
      ['--env-file', '.env', '.env'],
      ['--env-file-if-exists', '.env', '.env'],
      ['--test-concurrency', '2', '2'],
      ['--test-timeout', '5000', '5000'],
      ['--test-coverage-branches', '100', '100'],
      ['--test-coverage-functions', '100', '100'],
      ['--test-coverage-lines', '100', '100'],
      ['--experimental-test-coverage', '', false],
      ['--test-coverage-exclude', 'test/**', 'test/**'],
      ['--test-coverage-include', 'src/**', 'src/**'],
      ['--test-update-snapshots', '', true],
      ['--import', './index.js', './index.js'],
      ['--require', './index.js', './index.js'],
    ];

    for (const [flagName,
                testValue,
                expectedValue,
                propagatedFlag = flagName,
                testDescription = `should propagate ${flagName} to child tests as expected`] of flagPropagationTests) {

      it(testDescription, () => {
        const args = [
          '--test-reporter=tap',
          '--no-warnings',
          '--expose-internals',
          // We need to pass the flag that will be propagated to the child test
          testValue ? `${flagName}=${testValue}` : flagName,
          // Use the runner fixture
          runner,
          // Pass parameters to the fixture
          `--flag=${propagatedFlag}`,
          `--expected=${expectedValue}`,
          `--description="${testDescription}"`,
        ].filter(Boolean);

        const child = spawnSync(
          process.execPath,
          args,
          {
            cwd: fixtureDir,
          },
        );

        assert.strictEqual(child.status, 0, `Flag propagation test failed for ${flagName}.`);
        const stdout = child.stdout.toString();
        assert.match(stdout, /tests 1/, `Test should execute for ${flagName}`);
        assert.match(stdout, /pass 1/, `Test should pass for ${flagName} propagation check`);
      });
    }
  });

  describe('via config file', () => {
    const configFilePropagationTests = [
      ['--test-concurrency', 2, 2, 'test'],
      ['--test-timeout', 5000, 5000, 'test'],
      ['--test-coverage-branches', 100, 100, 'test'],
      ['--test-coverage-functions', 100, 100, 'test'],
      ['--test-coverage-lines', 100, 100, 'test'],
      ['--experimental-test-coverage', true, false, 'test'],
      ['--test-coverage-exclude', 'test/**', 'test/**', 'test'],
      ['--test-coverage-include', 'src/**', 'src/**', 'test'],
      ['--test-update-snapshots', true, true, 'test'],
      ['--test-concurrency', 3, 3, 'test'],
      ['--test-timeout', 2500, 2500, 'test'],
      ['--test-coverage-branches', 90, 90, 'test'],
      ['--test-coverage-functions', 85, 85, 'test'],
    ];

    for (const [flagName, configValue, expectedValue, namespace] of configFilePropagationTests) {
      const testDescription = `should propagate ${flagName} from config file (${namespace}) to child tests`;

      it(testDescription, () => {
        tmpdir.refresh();

        // Create a temporary config file
        const configFile = path.join(tmpdir.path, 'test-config.json');
        const configContent = {
          [namespace]: {
            [flagName.replace('--', '')]: configValue
          }
        };

        fs.writeFileSync(configFile, JSON.stringify(configContent, null, 2));

        const args = [
          '--test-reporter=tap',
          '--no-warnings',
          '--expose-internals',
          `--experimental-config-file=${configFile}`,
          runner,
          `--flag=${flagName}`,
          `--expected=${expectedValue}`,
          `--description="${testDescription}"`,
        ];

        const child = spawnSync(
          process.execPath,
          args,
          {
            cwd: fixtureDir,
          },
        );

        assert.strictEqual(child.status, 0, `Config file propagation test failed for ${flagName}.`);
        const stdout = child.stdout.toString();
        assert.match(stdout, /tests 1/, `Test should execute for config file ${flagName}`);
        assert.match(stdout, /pass 1/, `Test should pass for config file ${flagName} propagation check`);
      });
    }
  });

  describe('V8 specific flags', () => {
    const v8FlagTestFixture = path.join(fixtureDir, 'issue-60986.mjs');
    it('should propagate V8 only flags to child tests', () => {

      const child = spawnSync(
        process.execPath,
        [
          '--allow-natives-syntax',
          '--expose-gc',
          '--test',
          v8FlagTestFixture,
        ],
        {
          cwd: fixtureDir,
        },
      );

      assert.strictEqual(child.status, 0, `V8 flag propagation test failed.`);
      const stdout = child.stdout.toString();
      assert.match(stdout, /tests 1/, `Test should execute for V8 flag propagation`);
      assert.match(stdout, /pass 1/, `Test should pass for V8 flag propagation check`);
    });
  });
});
