// Copyright (c) 2022, 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.

// ignore: deprecated_member_use
import 'dart:cli' as cli;
import 'dart:convert';
import 'dart:io' as io;
import 'dart:typed_data';

import 'package:_fe_analyzer_shared/src/macros/bootstrap.dart';
import 'package:_fe_analyzer_shared/src/macros/executor/serialization.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
import 'package:analyzer/src/summary2/macro.dart';
import 'package:analyzer/src/util/uri.dart';
import 'package:analyzer_utilities/package_root.dart' as package_root;
import 'package:front_end/src/api_prototype/compiler_options.dart' as fe;
import 'package:front_end/src/api_prototype/file_system.dart' as fe;
import 'package:front_end/src/fasta/kernel/utils.dart' as fe;
import 'package:kernel/target/targets.dart' as fe;
import 'package:path/path.dart' as package_path;
import 'package:vm/kernel_front_end.dart' as fe;
import 'package:vm/target/vm.dart' as fe;

final Uri _platformDillUri = Uri.parse('org-dartlang-sdk://vm.dill');

/// Implementation of [MacroKernelBuilder] that can run in Dart SDK repository.
///
/// This is a temporary implementation, to be replaced with a more stable
/// approach, e.g. a `dart:` API for compilation, shipping `front_end`
/// with SDK, etc.
class DartRepositoryMacroKernelBuilder implements MacroKernelBuilder {
  final Uint8List platformDillBytes;

  DartRepositoryMacroKernelBuilder(this.platformDillBytes);

  @override
  Uint8List build({
    required MacroFileSystem fileSystem,
    required List<MacroLibrary> libraries,
  }) {
    var options = fe.CompilerOptions()
      ..sdkSummary = _platformDillUri
      ..target = fe.VmTarget(fe.TargetFlags(enableNullSafety: true));

    var macroMainContent = bootstrapMacroIsolate(
      {
        for (var library in libraries)
          library.uri.toString(): {
            for (var c in library.classes) c.name: c.constructors
          },
      },
      SerializationMode.byteDataClient,
    );

    var macroMainBytes = utf8.encode(macroMainContent) as Uint8List;
    var macroMainPath = '${libraries.first.path}.macro';
    var macroMainUri = fileSystem.pathContext.toUri(macroMainPath);

    options.fileSystem = _FileSystem(
      fileSystem,
      platformDillBytes,
      macroMainUri,
      macroMainBytes,
    );

    // TODO(scheglov) For now we convert async into sync.
    // ignore: deprecated_member_use
    var compilationResults = cli.waitFor(
      fe.compileToKernel(
        macroMainUri,
        options,
        environmentDefines: {},
      ),
    );

    return fe.serializeComponent(
      compilationResults.component!,
      filter: (library) {
        return !library.importUri.isScheme('dart');
      },
      includeSources: false,
    );
  }
}

/// Environment for compiling macros to kernels, expecting that we run
/// a test in the Dart SDK repository.
///
/// Just like [DartRepositoryMacroKernelBuilder], this is a temporary
/// implementation.
class MacrosEnvironment {
  static late final instance = MacrosEnvironment._();

  final _resourceProvider = MemoryResourceProvider(context: package_path.posix);
  late final Uint8List platformDillBytes;

  MacrosEnvironment._() {
    var physical = PhysicalResourceProvider.INSTANCE;

    var packageRoot = physical.pathContext.normalize(package_root.packageRoot);
    physical
        .getFolder(packageRoot)
        .getChildAssumingFolder('_fe_analyzer_shared/lib/src/macros')
        .copyTo(
          packageSharedFolder.getChildAssumingFolder('lib/src'),
        );

    platformDillBytes = physical
        .getFile(io.Platform.resolvedExecutable)
        .parent
        .parent
        .getChildAssumingFolder('lib')
        .getChildAssumingFolder('_internal')
        .getChildAssumingFile('vm_platform_strong.dill')
        .readAsBytesSync();
  }

  Folder get packageSharedFolder {
    return _resourceProvider.getFolder('/packages/_fe_analyzer_shared');
  }
}

class _BytesFileSystemEntity implements fe.FileSystemEntity {
  @override
  final Uri uri;

  final Uint8List bytes;

  _BytesFileSystemEntity(this.uri, this.bytes);

  @override
  Future<bool> exists() async => true;

  @override
  Future<bool> existsAsyncIfPossible() => exists();

  @override
  Future<List<int>> readAsBytes() async => bytes;

  @override
  Future<List<int>> readAsBytesAsyncIfPossible() => readAsBytes();

  @override
  Future<String> readAsString() async {
    var bytes = await readAsBytes();
    return utf8.decode(bytes);
  }
}

class _FileSystem implements fe.FileSystem {
  final MacroFileSystem fileSystem;
  final Uint8List platformDillBytes;
  final Uri macroMainUri;
  final Uint8List macroMainBytes;

  _FileSystem(
    this.fileSystem,
    this.platformDillBytes,
    this.macroMainUri,
    this.macroMainBytes,
  );

  @override
  fe.FileSystemEntity entityForUri(Uri uri) {
    if (uri == _platformDillUri) {
      return _BytesFileSystemEntity(uri, platformDillBytes);
    } else if (uri == macroMainUri) {
      return _BytesFileSystemEntity(uri, macroMainBytes);
    } else if (uri.isScheme('file')) {
      var path = fileUriToNormalizedPath(fileSystem.pathContext, uri);
      return _FileSystemEntity(
        uri,
        fileSystem.getFile(path),
      );
    } else {
      throw fe.FileSystemException(uri, 'Only supports file: URIs');
    }
  }
}

class _FileSystemEntity implements fe.FileSystemEntity {
  @override
  final Uri uri;

  final MacroFileEntry file;

  _FileSystemEntity(this.uri, this.file);

  @override
  Future<bool> exists() async => file.exists;

  @override
  Future<bool> existsAsyncIfPossible() => exists();

  @override
  Future<List<int>> readAsBytes() async {
    var string = await readAsString();
    return utf8.encode(string);
  }

  @override
  Future<List<int>> readAsBytesAsyncIfPossible() => readAsBytes();

  @override
  Future<String> readAsString() async => file.content;
}
