// Copyright 2014 The Flutter Authors. 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:io' as io;

import 'package:args/args.dart';
import 'package:conductor_core/conductor_core.dart';
import 'package:conductor_core/packages_autoroller.dart';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:meta/meta.dart' show visibleForTesting;
import 'package:platform/platform.dart';
import 'package:process/process.dart';

const String kTokenOption = 'token';
const String kGithubClient = 'github-client';
const String kMirrorRemote = 'mirror-remote';
const String kUpstreamRemote = 'upstream-remote';

Future<void> main(List<String> args) {
  return run(args);
}

@visibleForTesting
Future<void> run(
  List<String> args, {
  FileSystem fs = const LocalFileSystem(),
  ProcessManager processManager = const LocalProcessManager(),
}) async {
  final ArgParser parser = ArgParser();
  parser.addOption(
    kTokenOption,
    help: 'Path to GitHub access token file.',
    mandatory: true,
  );
  parser.addOption(
    kGithubClient,
    help: 'Path to GitHub CLI client. If not provided, it is assumed `gh` is '
        'present on the PATH.',
  );
  parser.addOption(
    kMirrorRemote,
    help: 'The mirror git remote that the feature branch will be pushed to. '
        'Required',
    mandatory: true,
  );
  parser.addOption(
    kUpstreamRemote,
    help: 'The upstream git remote that the feature branch will be merged to.',
    hide: true,
    defaultsTo: 'https://github.com/flutter/flutter.git',
  );

  final ArgResults results;
  try {
    results = parser.parse(args);
  } on FormatException {
    io.stdout.writeln('''
Usage:

${parser.usage}
''');
    rethrow;
  }

  final String mirrorUrl = results[kMirrorRemote]! as String;
  final String upstreamUrl = results[kUpstreamRemote]! as String;
  final String tokenPath = results[kTokenOption]! as String;
  final File tokenFile = fs.file(tokenPath);
  if (!tokenFile.existsSync()) {
    throw ArgumentError(
      'Provided token path $tokenPath but no file exists at ${tokenFile.absolute.path}',
    );
  }
  final String token = tokenFile.readAsStringSync().trim();
  if (token.isEmpty) {
    throw ArgumentError(
      'Tried to read a GitHub access token from file ${tokenFile.path} but it was empty',
    );
  }

  final FrameworkRepository framework = FrameworkRepository(
    _localCheckouts,
    mirrorRemote: Remote.mirror(mirrorUrl),
    upstreamRemote: Remote.upstream(upstreamUrl),
  );

  await PackageAutoroller(
    framework: framework,
    githubClient: results[kGithubClient] as String? ?? 'gh',
    orgName: _parseOrgName(mirrorUrl),
    token: token,
    processManager: processManager,
  ).roll();
}

String _parseOrgName(String remoteUrl) {
  final RegExp pattern = RegExp(r'^https:\/\/github\.com\/(.*)\/');
  final RegExpMatch? match = pattern.firstMatch(remoteUrl);
  if (match == null) {
    throw FormatException(
      'Malformed upstream URL "$remoteUrl", should start with "https://github.com/"',
    );
  }
  return match.group(1)!;
}

Checkouts get _localCheckouts {
  const FileSystem fileSystem = LocalFileSystem();
  const ProcessManager processManager = LocalProcessManager();
  const Platform platform = LocalPlatform();
  final Stdio stdio = VerboseStdio(
    stdout: io.stdout,
    stderr: io.stderr,
    stdin: io.stdin,
  );
  return Checkouts(
    fileSystem: fileSystem,
    parentDirectory: _localFlutterRoot.parent,
    platform: platform,
    processManager: processManager,
    stdio: stdio,
  );
}

Directory get _localFlutterRoot {
  String filePath;
  const FileSystem fileSystem = LocalFileSystem();
  const Platform platform = LocalPlatform();

  filePath = platform.script.toFilePath();
  final String checkoutsDirname = fileSystem.path.normalize(
    fileSystem.path.join(
      fileSystem.path.dirname(filePath), // flutter/dev/conductor/core/bin
      '..', // flutter/dev/conductor/core
      '..', // flutter/dev/conductor
      '..', // flutter/dev
      '..', // flutter
    ),
  );
  return fileSystem.directory(checkoutsDirname);
}

@visibleForTesting
void validateTokenFile(String filePath, [FileSystem fs = const LocalFileSystem()]) {

}
