// Copyright (c) 2019, 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:io';

import 'package:analyzer/src/lint/config.dart';
import 'package:analyzer/src/lint/registry.dart';
import 'package:github/server.dart';
import 'package:http/http.dart' as http;
import 'package:linter/src/analyzer.dart';
import 'package:linter/src/rules.dart';
import 'package:pub_semver/pub_semver.dart';
import 'package:yaml/yaml.dart';

const _allPathSuffix = '/example/all.yaml';
const _repoPathPrefix = 'https://raw.githubusercontent.com/dart-lang/linter/';
const _rulePathPrefix = 'https://raw.githubusercontent.com/dart-lang/linter';

const _flutterOptionsUrl =
    'https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/analysis_options_user.yaml';
const _flutterRepoOptionsUrl =
    'https://raw.githubusercontent.com/flutter/flutter/master/analysis_options.yaml';
const _pedanticOptionsUrl =
    'https://raw.githubusercontent.com/dart-lang/pedantic/master/lib/analysis_options.yaml';
const _stagehandOptionsUrl =
    'https://raw.githubusercontent.com/dart-lang/stagehand/master/templates/analysis_options.yaml';

int _latestMinor;

Map<String, List<String>> _sinceMap = <String, List<String>>{};

List<String> _flutterRules;
List<String> _flutterRepoRules;
List<String> _pedanticRules;
List<String> _stagehandRules;

Future<List<String>> get flutterRules async =>
    _flutterRules ??= await _fetchRules(_flutterOptionsUrl);

Future<List<String>> get flutterRepoRules async =>
    _flutterRepoRules ??= await _fetchRules(_flutterRepoOptionsUrl);

Future<List<String>> get pedanticRules async =>
    _pedanticRules ??= await _fetchRules(_pedanticOptionsUrl);

Future<List<String>> get stagehandRules async =>
    _stagehandRules ??= await _fetchRules(_stagehandOptionsUrl);

Future<int> get latestMinor async =>
    _latestMinor ??= await _readLatestMinorVersion();

List<String> _sdkTags;

Future<List<String>> get sdkTags async => _sdkTags ??= await _fetchSdkTags();

/// We don't care about SDKs previous to this bottom.
final Version bottomDartSdk = new Version(2, 0, 0);

Future<List<String>> _fetchSdkTags() {
  var github = createGitHubClient();
  var slug = RepositorySlug('dart-lang', 'sdk');

  return github.repositories.listTags(slug).map((t) => t.name).where((t) {
    // Filter on numeric release tags.
    if (!t.startsWith(new RegExp(r'\d+'))) {
      return false;
    }

    // Filter on bottom.
    try {
      var version = Version.parse(t);
      return version.compareTo(bottomDartSdk) >= 0;
    } on FormatException {
      return false;
    }
  }).toList();
}

Iterable<LintRule> _registeredLints;

Iterable<LintRule> get registeredLints {
  if (_registeredLints == null) {
    registerLintRules();
    _registeredLints = Registry.ruleRegistry;
  }
  return _registeredLints;
}

Future<String> findSinceDartSdk(String linterVersion) async =>
    await dartSdkForLinter(linterVersion);

Future<String> dartSdkForLinter(String version) async {
  var sdkVersions = <String>[];
  var sdks = await sdkTags;
  for (var sdk in sdks) {
    var linterVersion = await linterForDartSdk(sdk);
    if (linterVersion == version) {
      sdkVersions.add(sdk);
    }
  }

  sdkVersions.sort();
  return sdkVersions.isNotEmpty ? sdkVersions.first : null;
}

Future<String> findSinceLinter(String lint) async {
  // History recorded in `all.yaml` starts in minor 31.
  var rules_31 = await rulesForVersion(31);
  if (rules_31.contains(lint)) {
    var version = await _crawlForVersion(lint);
    if (version != null) {
      return version;
    }
  }

  var latest = await latestMinor;
  for (var minor = 31; minor <= latest; ++minor) {
    var rules = await rulesForVersion(minor);
    if (rules != null) {
      if (rules.contains(lint)) {
        return '0.1.$minor';
      }
    }
  }

  return null;
}

Future<int> _readLatestMinorVersion() async {
  var contents = await new File('pubspec.yaml').readAsString();
  YamlMap pubspec = loadYamlNode(contents);
  // 0.1.79 or 0.1.79-dev
  return int.parse(pubspec['version'].split('.').last.split('-').first);
}

Future<String> _crawlForVersion(String lint) async {
  var client = new http.Client();
  for (int minor = 1; minor < 31; ++minor) {
    var version = '0.1.$minor';
    var req =
        await client.get('$_rulePathPrefix/$version/lib/src/rules/$lint.dart');
    if (req.statusCode == 200) {
      return version;
    }
  }
  return null;
}

Future<List<String>> rulesForVersion(int minor) async {
  var version = '0.1.$minor';
  if (minor >= 31) {
    return _sinceMap[version] ??=
        await _fetchRules('$_repoPathPrefix$version$_allPathSuffix');
  }
  return null;
}

Map<String, String> _dartSdkToLinterMap = <String, String>{};

Future<String> linterForDartSdk(String sdk) async =>
    _dartSdkToLinterMap[sdk] ??= await _fetchLinterForVersion(sdk);

Future<String> _fetchLinterForVersion(String version) async {
  var deps = await _fetchDEPSforVersion(version);
  if (deps != null) {
    for (var line in deps.split('\n')) {
      if (line.trim().startsWith('"lint')) {
        // "linter_tag": "0.1.59",
        var split = line.trim().split('"linter_tag":');
        if (split.length == 2) {
          //  "0.1.59",
          return split[1].split('"')[1];
        }
      }
    }
  }
  return null;
}

Future<String> _fetchDEPSforVersion(String version) async {
  var client = new http.Client();
  //https://raw.githubusercontent.com/dart-lang/sdk/2.1.0-dev.1.0/DEPS
  var req = await client
      .get('https://raw.githubusercontent.com/dart-lang/sdk/$version/DEPS');
  return req.body;
}

Future<LintConfig> _fetchConfig(String url) async {
  var client = new http.Client();
  var req = await client.get(url);
  return processAnalysisOptionsFile(req.body);
}

Future<List<String>> _fetchRules(String optionsUrl) async {
  var config = await _fetchConfig(optionsUrl);
  if (config == null) {
    print('no config found for: $optionsUrl (SKIPPED)');
    return <String>[];
  }
  var rules = <String>[];
  for (var ruleConfig in config.ruleConfigs) {
    rules.add(ruleConfig.name);
  }
  return rules;
}
