// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:convert';
import 'dart:io';

import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
import 'package:native_test_helpers/native_test_helpers.dart';
import 'package:test/test.dart';

import '../hook/build.dart' as hook;

void main() {
  test(
    'build hook decodes percent-encoded package root paths',
    () async {
      final tempDir = await Directory.systemTemp.createTemp(
        'objective_c_hook_path',
      );
      addTearDown(() => tempDir.delete(recursive: true));

      final realPackageRoot = findPackageRoot('objective_c');
      const rootDirName = 'pkg%47root';
      final rootDir = Directory('${tempDir.path}/$rootDirName');
      await rootDir.create();
      final symlinkPath = '${rootDir.path}/objective_c';
      await Link(symlinkPath).create(realPackageRoot.toFilePath());
      final symlinkDir = Directory(symlinkPath);

      final encodedPath = symlinkPath.replaceAll('%', '%25');
      final encodedPackageRoot = Uri.parse(
        'file:///${encodedPath.substring(1)}/',
      );
      expect(encodedPackageRoot.toString(), contains('%2547'));

      final compilerLog = tempDir.uri.resolve('compiler_args.txt').toFilePath();
      File(compilerLog).writeAsStringSync('');
      final compilerScript = tempDir.uri.resolve('clang').toFilePath();
      File(compilerScript).writeAsStringSync('''#!/bin/sh
if [ "\$1" = "--version" ]; then
  echo "Apple clang version 15.0.0"
  exit 0
fi
log="$compilerLog"
out=""
prev=""
for arg in "\$@"; do
  if [ "\$prev" = "-o" ]; then
    out="\$arg"
  fi
  prev="\$arg"
  printf '%s\\n' "\$arg" >> "\$log"
done
if [ -n "\$out" ]; then
  mkdir -p "\$(dirname "\$out")"
  : > "\$out"
fi
exit 0
''');
      Process.runSync('chmod', ['+x', compilerScript]);

      final outputDirectoryShared = tempDir.uri.resolve('output_shared/');
      await Directory.fromUri(outputDirectoryShared).create();
      final outputFile = tempDir.uri.resolve('output.json');

      final inputBuilder = BuildInputBuilder()
        ..setupShared(
          packageRoot: encodedPackageRoot,
          packageName: 'objective_c',
          outputFile: outputFile,
          outputDirectoryShared: outputDirectoryShared,
        )
        ..setupBuildInput()
        ..config.setupBuild(linkingEnabled: false)
        ..addExtension(
          CodeAssetExtension(
            targetArchitecture: Architecture.current,
            targetOS: OS.macOS,
            linkModePreference: LinkModePreference.dynamic,
            macOS: MacOSCodeConfig(targetVersion: 13),
            cCompiler: CCompilerConfig(
              compiler: Uri.file(compilerScript),
              linker: Uri.file(compilerScript),
              archiver: Uri.file(compilerScript),
            ),
          ),
        );
      final input = inputBuilder.build();
      final inputFile = tempDir.uri.resolve('input.json');
      File.fromUri(inputFile).writeAsStringSync(json.encode(input.json));

      final originalCwd = Directory.current;
      Directory.current = symlinkDir;
      try {
        await (hook.main as dynamic)(['--config=${inputFile.toFilePath()}']);
      } finally {
        Directory.current = originalCwd;
      }

      final logLines = File(compilerLog).readAsLinesSync();
      final decodedSrc = '$symlinkPath/src/objective_c.c';
      expect(logLines, contains(decodedSrc));
      expect(logLines.any((line) => line.contains('%2547')), isFalse);

      final decodedUtil = '$symlinkPath/test/util.c';
      expect(logLines, isNot(contains(decodedUtil)));
    },
    skip: !Platform.isMacOS ? 'Requires macOS' : null,
  );
}
