// 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.

import 'dart:convert';

import 'package:analysis_server/lsp_protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/src/analytics/google_analytics_manager.dart';
import 'package:analysis_server/src/analytics/percentile_calculator.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/context_root.dart' as analyzer;
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:linter/src/rules.dart';
import 'package:telemetry/telemetry.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

void main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(GoogleAnalyticsManagerTest);
  });
}

@reflectiveTest
class GoogleAnalyticsManagerTest with ResourceProviderMixin {
  final analytics = _MockAnalytics();
  late final manager = GoogleAnalyticsManager(analytics);

  Folder get testPackageRoot => getFolder('/home/package');

  String get testPackageRootPath => testPackageRoot.path;

  void test_createAnalysisContexts_lints() {
    _createAnalysisOptionsFile(lints: [
      'avoid_dynamic_calls',
      'await_only_futures',
      'unawaited_futures'
    ]);
    var collection = _createContexts();
    _defaultStartup();
    manager.createdAnalysisContexts(collection.contexts);
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.lintUsageCounts(parameters: {
        'usageCounts':
            '{"avoid_dynamic_calls":1,"await_only_futures":1,"unawaited_futures":1}',
      }),
    ]);
  }

  void test_createAnalysisContexts_severityAdjustments() {
    _createAnalysisOptionsFile(errors: {
      'avoid_dynamic_calls': 'error',
      'await_only_futures': 'ignore',
    });
    var collection = _createContexts();
    _defaultStartup();
    manager.createdAnalysisContexts(collection.contexts);
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.severityAdjustments(parameters: {
        'adjustmentCounts':
            '{"AVOID_DYNAMIC_CALLS":{"ERROR":1},"AWAIT_ONLY_FUTURES":{"ignore":1}}',
      }),
    ]);
  }

  void test_plugin_request() {
    _defaultStartup();
    PluginManager.pluginResponseTimes[_MockPluginInfo('a')] = {
      'analysis.getNavigation': PercentileCalculator(),
    };
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.pluginRequest(parameters: {
        'pluginId': 'a',
        'method': 'analysis.getNavigation',
        'duration': _IsPercentiles(),
      }),
    ]);
    PluginManager.pluginResponseTimes.clear();
  }

  void test_server_notification() {
    _defaultStartup();
    manager.handledNotificationMessage(
        notification: NotificationMessage(
            clientRequestTime: 2,
            jsonrpc: '',
            method: Method.workspace_didCreateFiles),
        startTime: _now(),
        endTime: _now());
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.notification(parameters: {
        'latency': _IsPercentiles(),
        'method': Method.workspace_didCreateFiles.toString(),
        'duration': _IsPercentiles(),
      }),
    ]);
  }

  void test_server_request_analysisDidChangeWorkspaceFolders() {
    _defaultStartup();
    var params = DidChangeWorkspaceFoldersParams(
        event: WorkspaceFoldersChangeEvent(added: [], removed: []));
    var request = RequestMessage(
        jsonrpc: '',
        id: Either2.t1(1),
        method: Method.workspace_didChangeWorkspaceFolders,
        params: params.toJson());
    manager.startedRequestMessage(request: request, startTime: _now());
    manager
        .changedWorkspaceFolders(added: ['a', 'b', 'c'], removed: ['d', 'e']);
    manager.sentResponseMessage(
        response: ResponseMessage(jsonrpc: '', id: Either2.t1(1)));
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.request(parameters: {
        'latency': _IsPercentiles(),
        'method': Method.workspace_didChangeWorkspaceFolders.toString(),
        'duration': _IsPercentiles(),
        'added':
            '{"count":1,"percentiles":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}',
        'removed':
            '{"count":1,"percentiles":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]}',
      }),
    ]);
  }

  void test_server_request_analysisSetAnalysisRoots() {
    _defaultStartup();
    var params = AnalysisSetAnalysisRootsParams(['a', 'b', 'c'], ['d', 'e']);
    var request =
        Request('1', ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS, params.toJson());
    manager.startedRequest(request: request, startTime: _now());
    manager.startedSetAnalysisRoots(params);
    manager.sentResponse(response: Response('1'));
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.request(parameters: {
        'latency': _IsPercentiles(),
        'method': ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS,
        'duration': _IsPercentiles(),
        ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS_INCLUDED:
            '{"count":1,"percentiles":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}',
        ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS_EXCLUDED:
            '{"count":1,"percentiles":[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]}',
      }),
    ]);
  }

  void test_server_request_analysisSetPriorityFiles() {
    _defaultStartup();
    var params = AnalysisSetPriorityFilesParams(['a']);
    var request =
        Request('1', ANALYSIS_REQUEST_SET_PRIORITY_FILES, params.toJson());
    manager.startedRequest(request: request, startTime: _now());
    manager.startedSetPriorityFiles(params);
    manager.sentResponse(response: Response('1'));
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.request(parameters: {
        'latency': _IsPercentiles(),
        'method': ANALYSIS_REQUEST_SET_PRIORITY_FILES,
        'duration': _IsPercentiles(),
        ANALYSIS_REQUEST_SET_PRIORITY_FILES_FILES:
            '{"count":1,"percentiles":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]}',
      }),
    ]);
  }

  void test_server_request_editGetRefactoring() {
    _defaultStartup();
    var params =
        EditGetRefactoringParams(RefactoringKind.RENAME, '', 0, 0, true);
    var request = Request('1', EDIT_REQUEST_GET_REFACTORING, params.toJson());
    manager.startedRequest(request: request, startTime: _now());
    manager.startedGetRefactoring(params);
    manager.sentResponse(response: Response('1'));
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.request(parameters: {
        'latency': _IsPercentiles(),
        'method': EDIT_REQUEST_GET_REFACTORING,
        'duration': _IsPercentiles(),
        EDIT_REQUEST_GET_REFACTORING_KIND: '{"RENAME":1}',
      }),
    ]);
  }

  void test_server_request_initialize() {
    _defaultStartup();
    var params = InitializeParams(
        capabilities: ClientCapabilities(),
        initializationOptions: {
          'closingLabels': true,
          'notAnOption': true,
          'onlyAnalyzeProjectsWithOpenFiles': true,
        });
    manager.initialize(params);
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(parameters: {
        'parameters':
            'closingLabels,onlyAnalyzeProjectsWithOpenFiles,suggestFromUnimportedLibraries',
      }),
    ]);
  }

  void test_server_request_initialized() {
    _defaultStartup();
    var params = InitializedParams();
    var request = RequestMessage(
        jsonrpc: '',
        id: Either2.t1(1),
        method: Method.initialized,
        params: params.toJson());
    manager.startedRequestMessage(request: request, startTime: _now());
    manager.initialized(openWorkspacePaths: ['a', 'b', 'c']);
    manager.sentResponseMessage(
        response: ResponseMessage(jsonrpc: '', id: Either2.t1(1)));
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.request(parameters: {
        'latency': _IsPercentiles(),
        'method': Method.initialized.toString(),
        'duration': _IsPercentiles(),
        'openWorkspacePaths':
            '{"count":1,"percentiles":[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]}',
      }),
    ]);
  }

  void test_server_request_noAdditional() {
    _defaultStartup();
    manager.startedRequest(
        request: Request('1', SERVER_REQUEST_SHUTDOWN), startTime: _now());
    manager.sentResponse(response: Response('1'));
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(),
      _ExpectedEvent.request(parameters: {
        'latency': _IsPercentiles(),
        'method': SERVER_REQUEST_SHUTDOWN,
        'duration': _IsPercentiles(),
      }),
    ]);
  }

  void test_shutdownWithoutStartup() {
    manager.shutdown();
    analytics.assertNoEvents();
  }

  void test_startup_withoutVersion() {
    var arguments = ['a', 'b'];
    var clientId = 'clientId';
    var sdkVersion = 'sdkVersion';
    manager.startUp(
        time: DateTime.now(),
        arguments: arguments,
        clientId: clientId,
        clientVersion: null,
        sdkVersion: sdkVersion);
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(parameters: {
        'flags': arguments.join(','),
        'clientId': clientId,
        'clientVersion': '',
        'sdkVersion': sdkVersion,
        'duration': _IsStringEncodedPositiveInt(),
      }),
    ]);
  }

  void test_startup_withPlugins() {
    _defaultStartup();
    manager.changedPlugins(_MockPluginManager(plugins: [
      _MockPluginInfo('a'),
      _MockPluginInfo('b'),
    ]));
    manager.shutdown();
    var counts =
        '{"count":1,"percentiles":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}';
    analytics.assertEvents([
      _ExpectedEvent.session(parameters: {
        'plugins': '{"recordCount":1,"rootCounts":{"a":$counts,"b":$counts}}'
      }),
    ]);
  }

  void test_startup_withVersion() {
    var arguments = ['a', 'b'];
    var clientId = 'clientId';
    var clientVersion = 'clientVersion';
    var sdkVersion = 'sdkVersion';
    manager.startUp(
        time: DateTime.now(),
        arguments: arguments,
        clientId: clientId,
        clientVersion: clientVersion,
        sdkVersion: sdkVersion);
    manager.shutdown();
    analytics.assertEvents([
      _ExpectedEvent.session(parameters: {
        'flags': arguments.join(','),
        'clientId': clientId,
        'clientVersion': clientVersion,
        '': isNull,
        'sdkVersion': sdkVersion,
        'duration': _IsStringEncodedPositiveInt(),
      }),
    ]);
  }

  /// Create an analysis options file based on the given arguments.
  void _createAnalysisOptionsFile({
    String? path,
    Map<String, String>? errors,
    List<String>? experiments,
    bool? implicitCasts,
    List<String>? lints,
  }) {
    path ??= '$testPackageRootPath/analysis_options.yaml';
    var buffer = StringBuffer();

    if (errors != null || experiments != null || implicitCasts != null) {
      buffer.writeln('analyzer:');
    }

    if (errors != null) {
      buffer.writeln('  errors:');
      for (var entry in errors.entries) {
        buffer.writeln('    ${entry.key}: ${entry.value}');
      }
    }

    if (experiments != null) {
      buffer.writeln('  enable-experiment:');
      for (var experiment in experiments) {
        buffer.writeln('    - $experiment');
      }
    }

    if (implicitCasts != null) {
      buffer.writeln('  strong-mode:');
      buffer.writeln('    implicit-casts: $implicitCasts');
    }

    if (lints != null) {
      buffer.writeln('linter:');
      buffer.writeln('  rules:');
      for (var lint in lints) {
        buffer.writeln('    - $lint');
      }
    }

    newFile(path, buffer.toString());
  }

  AnalysisContextCollection _createContexts() {
    var sdkRoot = getFolder('/sdk');
    createMockSdk(resourceProvider: resourceProvider, root: sdkRoot);
    registerLintRules();
    return AnalysisContextCollection(
        resourceProvider: resourceProvider,
        includedPaths: [testPackageRootPath],
        sdkPath: sdkRoot.path);
  }

  void _defaultStartup() {
    manager.startUp(
        time: DateTime.now(),
        arguments: [],
        clientId: '',
        clientVersion: null,
        sdkVersion: '');
  }

  DateTime _now() => DateTime.now();
}

/// A record of an event that was reported to analytics.
class _Event {
  final String category;
  final String action;
  final String? label;
  final int? value;
  final Map<String, String>? parameters;

  _Event(this.category, this.action, this.label, this.value, this.parameters);
}

/// A record of an event that was reported to analytics.
class _ExpectedEvent {
  final String category;
  final String action;
  final String? label;
  final int? value;
  final Map<String, Object>? parameters;

  _ExpectedEvent(this.category, this.action,
      {this.label, // ignore: unused_element
      this.value, // ignore: unused_element
      this.parameters});

  _ExpectedEvent.lintUsageCounts({Map<String, Object>? parameters})
      : this('language_server', 'lintUsageCounts', parameters: parameters);

  _ExpectedEvent.notification({Map<String, Object>? parameters})
      : this('language_server', 'notification', parameters: parameters);

  _ExpectedEvent.pluginRequest({Map<String, Object>? parameters})
      : this('language_server', 'pluginRequest', parameters: parameters);

  _ExpectedEvent.request({Map<String, Object>? parameters})
      : this('language_server', 'request', parameters: parameters);

  _ExpectedEvent.session({Map<String, Object>? parameters})
      : this('language_server', 'session', parameters: parameters);

  _ExpectedEvent.severityAdjustments({Map<String, Object>? parameters})
      : this('language_server', 'severityAdjustments', parameters: parameters);

  /// Compare the expected event with the [actual] event, failing if the actual
  /// doesn't match the expected.
  void matches(_Event actual) {
    expect(actual.category, category);
    expect(actual.action, action);
    if (label != null) {
      expect(actual.label, label);
    }
    if (value != null) {
      expect(actual.value, value);
    }
    final actualParameters = actual.parameters;
    final expectedParameters = parameters;
    if (expectedParameters != null) {
      if (actualParameters == null) {
        fail('Expected parameters but found none');
      }
      for (var expectedKey in expectedParameters.keys) {
        var actualValue = actualParameters[expectedKey];
        var expectedValue = expectedParameters[expectedKey];
        expect(actualValue, expectedValue, reason: 'For key $expectedKey');
      }
    }
  }

  @override
  String toString() {
    var buffer = StringBuffer();
    buffer.write('category: ');
    buffer.writeln(category);
    buffer.write('action: ');
    buffer.writeln(action);
    buffer.write('label: ');
    buffer.writeln(label);
    buffer.write('value: ');
    buffer.writeln(value);
    var parameterMap = parameters;
    if (parameterMap != null) {
      for (var entry in parameterMap.entries) {
        buffer.write('value: ');
        buffer.writeln('${entry.key}: ${entry.value}');
      }
    }
    return buffer.toString();
  }
}

/// A matcher for strings containing positive integer values.
class _IsPercentiles extends Matcher {
  const _IsPercentiles();

  @override
  Description describe(Description description) =>
      description.add('percentiles');

  @override
  bool matches(Object? item, Map matchState) {
    if (item is! String) {
      return false;
    }
    var map = json.decode(item);
    if (map is! Map || map.length != 2) {
      return false;
    }
    if (map['count'] is! int) {
      return false;
    }
    var percentiles = map['percentiles'];
    if (percentiles is! List || percentiles.length != 20) {
      return false;
    }
    return !percentiles.any((element) => element is! int);
  }
}

/// A matcher for strings containing positive integer values.
class _IsStringEncodedPositiveInt extends Matcher {
  const _IsStringEncodedPositiveInt();

  @override
  Description describe(Description description) =>
      description.add('a string encoded positive integer');

  @override
  bool matches(Object? item, Map matchState) {
    if (item is! String) {
      return false;
    }
    try {
      var value = int.parse(item);
      return value >= 0;
    } catch (exception) {
      return false;
    }
  }
}

/// An implementation of [Analytics] specialized for testing.
class _MockAnalytics implements Analytics {
  List<_Event> events = [];

  _MockAnalytics();

  void assertEvents(List<_ExpectedEvent> expectedEvents) {
    var expectedCount = expectedEvents.length;
    expect(events, hasLength(expectedCount));
    for (int i = 0; i < expectedCount; i++) {
      expectedEvents[i].matches(events[i]);
    }
  }

  void assertNoEvents() {
    expect(events, isEmpty);
  }

  @override
  void close() {
    // ignored
  }

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);

  @override
  Future sendEvent(String category, String action,
      {String? label, int? value, Map<String, String>? parameters}) async {
    events.add(_Event(category, action, label, value, parameters));
  }

  @override
  Future waitForLastPing({Duration? timeout}) async {
    // ignored
  }
}

class _MockPluginInfo implements PluginInfo {
  @override
  String pluginId;

  _MockPluginInfo(this.pluginId);

  @override
  Set<analyzer.ContextRoot> get contextRoots => {};

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

class _MockPluginManager implements PluginManager {
  @override
  List<PluginInfo> plugins;

  _MockPluginManager({this.plugins = const []});

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
