// 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:async';

import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/handler/legacy/legacy_handler.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/src/utilities/formatter.dart';
import 'package:dart_style/dart_style.dart' hide TrailingCommas;

/// The handler for the `edit.format` request.
class EditFormatHandler extends LegacyHandler {
  /// Initialize a newly created handler to be able to service requests for the
  /// [server].
  new(super.server, super.request, super.cancellationToken, super.performance);

  @override
  Future<void> handle() async {
    var params = EditFormatParams.fromRequest(
      request,
      clientUriConverter: server.uriConverter,
    );
    var file = params.file;

    var driver = server.getAnalysisDriver(file);
    var unit = driver?.parseFileSync(file);
    if (unit is! ParsedUnitResult) {
      sendResponse(Response.formatInvalidFile(request));
      return;
    }

    int? start = params.selectionOffset;
    int? length = params.selectionLength;

    // No need to preserve 0,0 selection
    if (start == 0 && length == 0) {
      start = null;
      length = null;
    }

    var formatter = createFormatter(unit, defaultPageWidth: params.lineLength);
    var unformattedCode = unit.content;
    SourceCode formattedResult;
    try {
      formattedResult = formatter.formatSource(
        SourceCode(
          unformattedCode,
          selectionStart: start,
          selectionLength: length,
        ),
      );
    } on FormatterException {
      sendResponse(Response.formatWithErrors(request));
      return;
    }
    var formattedSource = formattedResult.text;

    var edits = <SourceEdit>[];

    if (formattedSource != unformattedCode) {
      // TODO(brianwilkerson): replace full replacements with smaller, more targeted edits
      var edit = SourceEdit(0, unformattedCode.length, formattedSource);
      edits.add(edit);
    }

    var newStart = formattedResult.selectionStart;
    var newLength = formattedResult.selectionLength;

    // Sending null start/length values would violate protocol, so convert back
    // to 0.
    newStart ??= 0;
    newLength ??= 0;

    sendResult(EditFormatResult(edits, newStart, newLength));
  }
}
