// Copyright (c) 2023, 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 'package:clock/clock.dart';
import 'package:convert/convert.dart';
import 'package:file/file.dart';

import 'initializer.dart';
import 'utils.dart';

/// The regex pattern used to parse the disable analytics line.
const String telemetryFlagPattern = r'^reporting=([0|1]) *$';

/// The regex pattern used to parse the tools info
/// from the configuration file.
///
/// Example:
/// ```text
/// flutter-tool=2022-10-26,1
/// devtools=2022-11-26,1
/// ```
const String toolPattern =
    r'^([A-Za-z0-9]+[A-Za-z0-9_-]*)=([0-9]{4}-[0-9]{2}-[0-9]{2}),([0-9]+)$';

class ConfigHandler {
  /// Regex pattern implementation for matching a line in the config file.
  static RegExp telemetryFlagRegex = RegExp(
    telemetryFlagPattern,
    multiLine: true,
  );
  static RegExp toolRegex = RegExp(toolPattern, multiLine: true);

  final Directory homeDirectory;
  final File configFile;

  final Map<String, ToolInfo> parsedTools = <String, ToolInfo>{};

  DateTime configFileLastModified;

  /// Reporting enabled unless specified by user
  bool _telemetryEnabled = true;

  ConfigHandler({required this.homeDirectory, required this.configFile})
    : configFileLastModified = configFile.lastModifiedSync() {
    // Call the method to parse the contents of the config file when
    // this class is initialized
    parseConfig();
  }

  /// Returns the telemetry state from the config file.
  ///
  /// Method will reparse the config file if it detects that the
  /// last modified datetime is different from what was parsed when
  /// the class was initialized.
  bool get telemetryEnabled {
    if (configFileLastModified.isBefore(configFile.lastModifiedSync())) {
      parseConfig();
      configFileLastModified = configFile.lastModifiedSync();
    }

    return _telemetryEnabled;
  }

  /// Responsibe for the creation of the configuration line
  /// for the tool being passed in by the user and adding a
  /// [ToolInfo] object.
  void addTool({required String tool, required int versionNumber}) {
    // Create the new instance of [ToolInfo] to be added
    // to the [parsedTools] map
    parsedTools[tool] = ToolInfo(
      lastRun: clock.now(),
      versionNumber: versionNumber,
    );

    // New string to be appended to the bottom of the configuration file
    // with a newline character for new tools to be added
    var newTool = '$tool=$dateStamp,$versionNumber\n';
    if (!configFile.readAsStringSync().endsWith('\n')) {
      newTool = '\n$newTool';
    }
    configFile.writeAsStringSync(newTool, mode: FileMode.append);
    configFileLastModified = configFile.lastModifiedSync();
  }

  /// Will increment the version number and update the date
  /// in the config file for the provided tool name while
  /// also incrementing the version number in [ToolInfo].
  void incrementToolVersion({
    required String tool,
    required int newVersionNumber,
  }) {
    if (!parsedTools.containsKey(tool)) {
      return;
    }

    // Read in the config file contents and use a regex pattern to
    // match the line for the current tool (ie. flutter-tools=2023-01-05,1)
    final configString = configFile.readAsStringSync();
    final pattern = '^($tool)=([0-9]{4}-[0-9]{2}-[0-9]{2}),([0-9]+)\$';

    final regex = RegExp(pattern, multiLine: true);
    final matches = regex.allMatches(configString);

    // If there isn't exactly one match for the given tool, that suggests the
    // file has been altered and needs to be reset
    if (matches.length != 1) {
      resetConfig();
      return;
    }

    // Construct the new tool line for the config line and replace it
    // in the original config string to prep for writing back out
    final newToolString = '$tool=$dateStamp,$newVersionNumber';
    final newConfigString = configString.replaceAll(regex, newToolString);
    configFile.writeAsStringSync(newConfigString);

    final toolInfo = parsedTools[tool];
    if (toolInfo == null) {
      return;
    }

    // Update the [ToolInfo] object for the current tool
    toolInfo.lastRun = clock.now();
    toolInfo.versionNumber = newVersionNumber;
  }

  /// Method responsible for reading in the config file stored on
  /// user's machine and parsing out the following: all the tools that
  /// have been logged in the file, the dates they were last run, and
  /// determining if telemetry is enabled by parsing the file.
  void parseConfig() {
    // Begin with the assumption that telemetry is always enabled
    _telemetryEnabled = true;

    // Read the configuration file as a string and run the two regex patterns
    // on it to get information around which tools have been parsed and whether
    // or not telemetry has been disabled by the user
    final configString = configFile.readAsStringSync();

    // Collect the tools logged in the configuration file
    toolRegex.allMatches(configString).forEach((RegExpMatch element) {
      // Extract the information relevant for the [ToolInfo] class
      final tool = element.group(1) as String;
      final lastRun = DateTime.parse(element.group(2) as String);
      final versionNumber = int.parse(element.group(3) as String);

      // Initialize an instance of the [ToolInfo] class to store
      // in the [parsedTools] map object
      parsedTools[tool] = ToolInfo(
        lastRun: lastRun,
        versionNumber: versionNumber,
      );
    });

    // Check for lines signaling that the user has disabled analytics,
    // if multiple lines are found, the more conservative value will be used
    telemetryFlagRegex.allMatches(configString).forEach((RegExpMatch element) {
      // Conditional for recording telemetry as being disabled
      if (element.group(1) == '0') {
        _telemetryEnabled = false;
      }
    });
  }

  /// This will reset the configuration file and clear the
  /// [parsedTools] map and trigger parsing the config again.
  void resetConfig() {
    createConfigFile(configFile: configFile, homeDirectory: homeDirectory);
    parsedTools.clear();
    parseConfig();
  }

  /// Disables the reporting capabilities if [reportingBool] is set to `false`.
  Future<void> setTelemetry(bool reportingBool) async {
    final flag = reportingBool ? '1' : '0';
    final configString = await configFile.readAsString();

    final matches = telemetryFlagRegex.allMatches(configString);

    // If there isn't exactly one match for the reporting flag, that suggests
    // the file has been altered and needs to be reset
    if (matches.length != 1) {
      resetConfig();
      return;
    }

    final newTelemetryString = 'reporting=$flag';

    final newConfigString = configString.replaceAll(
      telemetryFlagRegex,
      newTelemetryString,
    );

    await configFile.writeAsString(newConfigString);
    configFileLastModified = configFile.lastModifiedSync();

    _telemetryEnabled = reportingBool;
  }
}

class ToolInfo {
  DateTime lastRun;
  int versionNumber;

  ToolInfo({required this.lastRun, required this.versionNumber});

  @override
  String toString() {
    return json.encode(<String, Object?>{
      'lastRun': FixedDateTimeFormatter('YYYY-MM-DD').encode(lastRun),
      'versionNumber': versionNumber,
    });
  }
}
