import 'dart:io';
import 'package:test/test.dart';

void main() {
  final scriptFile = File('assets/script/powershell/oto_agent_bootstrap.ps1');

  group('Windows PowerShell Bootstrap Script Contract Tests', () {
    late String content;

    setUpAll(() async {
      expect(
        await scriptFile.exists(),
        isTrue,
        reason: 'PowerShell bootstrap script file must exist',
      );
      content = await scriptFile.readAsString();
    });

    test('should contain required flags', () {
      expect(content, contains('--token'));
      expect(content, contains('--server-url'));
      expect(content, contains('--agent-id'));
      expect(content, isNot(contains('--enrollment-token')));
      expect(content, contains('--release-base-url'));
    });

    test('should contain optional flags', () {
      expect(content, contains('--agent-alias'));
      expect(content, contains('--install-dir'));
      expect(content, contains('--config-path'));
      expect(content, contains('--workspace-root'));
      expect(content, contains('--log-dir'));
      expect(content, contains('--no-background'));
    });

    test(
      'should support Windows x64 and arm64 zip assets via dynamic arch combination',
      () {
        expect(content, contains("'x64'"));
        expect(content, contains("'arm64'"));
        expect(content, contains('oto-windows-'));
        expect(content, contains('.zip'));
        expect(content, contains(r'"oto-windows-$archName.zip"'));
      },
    );

    test('should detect architecture via PROCESSOR_ARCHITECTURE', () {
      expect(content, contains('PROCESSOR_ARCHITECTURE'));
      expect(content, contains('AMD64'));
      expect(content, contains('ARM64'));
      expect(content, contains("'x64'"));
      expect(content, contains("'arm64'"));
    });

    test('should fail with unsupported architecture message', () {
      expect(content, contains('Unsupported architecture:'));
    });

    test('should validate HTTPS for release-base-url', () {
      expect(content, contains('https://'));
      expect(content, contains('--release-base-url must use https://'));
    });

    test('should write expected keys to configuration yaml', () {
      expect(content, contains('agent:'));
      expect(content, contains('id:'));
      expect(content, contains('alias:'));
      expect(content, contains('enrollment_token:'));
      expect(content, contains('server:'));
      expect(content, contains('url:'));
      expect(content, contains('runtime:'));
      expect(content, contains('install_dir:'));
      expect(content, contains('workspace_root:'));
      expect(content, contains('log_dir:'));
    });

    test('should escape YAML single-quoted config values', () {
      expect(content, contains(r'''.Replace("'", "''")'''));
      expect(content, contains(r"id: '$agentIdYaml'"));
      expect(content, contains(r"enrollment_token: '$enrollmentTokenYaml'"));
      expect(content, contains(r"serverUrlYaml = $serverUrl.Replace("));
    });

    test('should contain agent runtime command and background behavior', () {
      expect(content, contains('agent run'));
      expect(content, contains('--config'));
      expect(content, contains('oto-agent.pid'));
    });

    test(
      'should use separate stdout and stderr log files for background process',
      () {
        expect(content, contains('RedirectStandardOutput'));
        expect(content, contains('RedirectStandardError'));
        expect(content, contains('oto-agent.out.log'));
        expect(content, contains('oto-agent.err.log'));
      },
    );

    test('should contain binary verification before background execution', () {
      expect(content, contains('Verifying OTO binary...'));
      expect(content, contains('Start-Process'));
      expect(content, contains('--version'));
      expect(content, contains('ExitCode -ne 0'));
      expect(content, contains('Error: OTO binary verification failed.'));
    });

    test('should apply ACL hardening to config file after write', () {
      expect(content, contains('SetAccessRuleProtection'));
      expect(content, contains('FileSystemAccessRule'));
      expect(content, contains('Set-Acl'));
    });

    test('should not expose enrollment token in write/output statements', () {
      final lines = content.split('\n');
      for (final line in lines) {
        final trimmed = line.trim();
        // Skip the config write block that intentionally contains the token key
        if (trimmed.contains('enrollment_token:') &&
            trimmed.contains(r'"$enrollmentToken"')) {
          continue;
        }
        // No Write-Host / Write-Error / Write-Output line should directly print
        // the enrollment token variable outside config file construction.
        if (trimmed.startsWith('Write-Host') ||
            trimmed.startsWith('Write-Error') ||
            trimmed.startsWith('Write-Output')) {
          expect(
            trimmed,
            isNot(contains(r'$enrollmentToken')),
            reason:
                'Output statement must not expose enrollment token: $trimmed',
          );
        }
      }
    });
  });
}
