// Copyright (c) 2018, 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 'package:analysis_server/plugin/edit/assist/assist_core.dart';
import 'package:analysis_server/plugin/edit/assist/assist_dart.dart';
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/assist_internal.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/fix_internal.dart';
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/ast_provider_driver.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/lint/linter.dart';
import 'package:analyzer/src/lint/linter_visitor.dart';
import 'package:analyzer/src/lint/registry.dart';
import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
    show SourceChange, SourceEdit, SourceFileEdit;
import 'package:front_end/src/fasta/fasta_codes.dart';
import 'package:front_end/src/scanner/token.dart';
import 'package:source_span/src/span.dart';

class EditDartFix {
  final AnalysisServer server;
  final Request request;
  final fixFolders = <Folder>[];
  final fixFiles = <File>[];

  List<String> descriptionOfFixes;
  List<String> otherRecommendations;
  SourceChange sourceChange;

  EditDartFix(this.server, this.request);

  void addFix(String description, SourceChange change) {
    descriptionOfFixes.add(description);
    for (SourceFileEdit fileEdit in change.edits) {
      for (SourceEdit sourceEdit in fileEdit.edits) {
        sourceChange.addEdit(fileEdit.file, fileEdit.fileStamp, sourceEdit);
      }
    }
  }

  void addRecommendation(String recommendation) {
    otherRecommendations.add(recommendation);
  }

  Future<Response> compute() async {
    final params = new EditDartfixParams.fromRequest(request);

    // Validate each included file and directory.
    final resourceProvider = server.resourceProvider;
    final contextManager = server.contextManager;
    for (String filePath in params.included) {
      if (!server.isValidFilePath(filePath)) {
        return new Response.invalidFilePathFormat(request, filePath);
      }
      Resource res = resourceProvider.getResource(filePath);
      if (!res.exists ||
          !(contextManager.includedPaths.contains(filePath) ||
              contextManager.isInAnalysisRoot(filePath))) {
        return new Response.fileNotAnalyzed(request, filePath);
      }
      if (res is Folder) {
        fixFolders.add(res);
      } else {
        fixFiles.add(res);
      }
    }

    // Get the desired lints
    final LintRule preferMixin = Registry.ruleRegistry['prefer_mixin'];
    if (preferMixin == null) {
      return new Response.serverError(
          request, 'Missing prefer_mixin lint', null);
    }
    final preferMixinFix = new PreferMixinFix(this);
    preferMixin.reporter = preferMixinFix;

    // Setup
    final linters = <Linter>[
      preferMixin,
    ];
    final fixes = <LinterFix>[
      preferMixinFix,
    ];
    final visitors = <AstVisitor>[];
    final registry = new NodeLintRegistry(false);
    for (Linter linter in linters) {
      final visitor = linter.getVisitor();
      if (visitor != null) {
        visitors.add(visitor);
      }
      if (linter is NodeLintRule) {
        (linter as NodeLintRule).registerNodeProcessors(registry);
      }
    }
    final AstVisitor astVisitor = visitors.isNotEmpty
        ? new ExceptionHandlingDelegatingAstVisitor(
            visitors, ExceptionHandlingDelegatingAstVisitor.logException)
        : null;
    final AstVisitor linterVisitor = new LinterVisitor(
        registry, ExceptionHandlingDelegatingAstVisitor.logException);

    // TODO(danrubel): Determine if a lint is configured to run as part of
    // standard analysis and use those results if available instead of
    // running the lint again.

    // Analyze each source file.
    final resources = <Resource>[];
    for (String rootPath in contextManager.includedPaths) {
      resources.add(resourceProvider.getResource(rootPath));
    }
    descriptionOfFixes = <String>[];
    otherRecommendations = <String>[];
    sourceChange = new SourceChange('dartfix');
    bool hasErrors = false;
    while (resources.isNotEmpty) {
      Resource res = resources.removeLast();
      if (res is Folder) {
        for (Resource child in res.getChildren()) {
          if (!child.shortName.startsWith('.') &&
              contextManager.isInAnalysisRoot(child.path)) {
            resources.add(child);
          }
        }
        continue;
      }
      AnalysisResult result = await server.getAnalysisResult(res.path);
      CompilationUnit unit = result?.unit;
      if (unit != null) {
        if (!hasErrors) {
          for (AnalysisError error in result.errors) {
            if (!(await fixError(result, error))) {
              if (error.errorCode.type == ErrorType.SYNTACTIC_ERROR) {
                hasErrors = true;
              }
            }
          }
        }
        Source source = result.sourceFactory.forUri2(result.uri);
        for (Linter linter in linters) {
          linter.reporter.source = source;
        }
        if (astVisitor != null) {
          unit.accept(astVisitor);
        }
        unit.accept(linterVisitor);
      }
    }

    // Cleanup
    for (Linter linter in linters) {
      linter.reporter = null;
    }

    // Apply distributed fixes
    for (LinterFix fix in fixes) {
      await fix.applyFix();
    }

    return new EditDartfixResult(descriptionOfFixes, otherRecommendations,
            hasErrors, sourceChange.edits)
        .toResponse(request.id);
  }

  Future<bool> fixError(AnalysisResult result, AnalysisError error) async {
    if (error.errorCode ==
        StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR) {
      // TODO(danrubel): Rather than comparing the error codes individually,
      // it would be better if each error code could specify
      // whether or not it could be fixed automatically.

      // Fall through to calculate and apply the fix
    } else {
      // This error cannot be automatically fixed
      return false;
    }

    final location = '${locationDescription(result, error.offset)}';
    final dartContext = new DartFixContextImpl(
        new FixContextImpl(
            server.resourceProvider, result.driver, error, result.errors),
        new AstProviderForDriver(result.driver),
        result.unit);
    final processor = new FixProcessor(dartContext);
    Fix fix = await processor.computeFix();
    if (fix != null) {
      addFix('${fix.change.message} in $location', fix.change);
    } else {
      // TODO(danrubel): Determine why the fix could not be applied
      // and report that in the description.
      addRecommendation('Could not fix "${error.message}" in $location');
    }
    return true;
  }

  /// Return `true` if the path in within the set of `included` files
  /// or is within an `included` directory.
  bool isIncluded(String filePath) {
    if (filePath != null) {
      for (File file in fixFiles) {
        if (file.path == filePath) {
          return true;
        }
      }
      for (Folder folder in fixFolders) {
        if (folder.contains(filePath)) {
          return true;
        }
      }
    }
    return false;
  }

  /// Return a human readable description of the specified offset and file.
  String locationDescription(AnalysisResult result, int offset) {
    // TODO(danrubel): Pass the location back to the client along with the
    // message indicating what was or was not automatically fixed
    // rather than interpreting and integrating the location into the message.
    final description = new StringBuffer();
    // Determine the relative path
    for (Folder folder in fixFolders) {
      if (folder.contains(result.path)) {
        description.write(server.resourceProvider.pathContext
            .relative(result.path, from: folder.path));
        break;
      }
    }
    if (description.isEmpty) {
      description.write(result.path);
    }
    // Determine the line and column number
    if (offset >= 0) {
      final loc = result.unit.lineInfo.getLocation(offset);
      description.write(':${loc.lineNumber}');
    }
    return description.toString();
  }
}

class EditDartFixAssistContext implements DartAssistContext {
  @override
  final AnalysisDriver analysisDriver;

  @override
  final int selectionLength;

  @override
  final int selectionOffset;

  @override
  final Source source;

  @override
  final CompilationUnit unit;

  EditDartFixAssistContext(
      EditDartFix dartFix, this.source, this.unit, AstNode node)
      : analysisDriver = dartFix.server.getAnalysisDriver(source.fullName),
        selectionOffset = node.offset,
        selectionLength = 0;
}

abstract class LinterFix implements ErrorReporter {
  final EditDartFix dartFix;

  @override
  Source source;

  LinterFix(this.dartFix);

  Future<void> applyFix();

  @override
  void reportError(AnalysisError error) {
    // ignored
  }

  @override
  void reportErrorForElement(ErrorCode errorCode, Element element,
      [List<Object> arguments]) {
    // ignored
  }

  @override
  void reportErrorForNode(ErrorCode errorCode, AstNode node,
      [List<Object> arguments]) {
    // ignored
  }

  @override
  void reportErrorForOffset(ErrorCode errorCode, int offset, int length,
      [List<Object> arguments]) {
    // ignored
  }

  @override
  void reportErrorForSpan(ErrorCode errorCode, SourceSpan span,
      [List<Object> arguments]) {
    // ignored
  }

  @override
  void reportErrorForToken(ErrorCode errorCode, Token token,
      [List<Object> arguments]) {
    // ignored
  }

  @override
  void reportErrorMessage(
      ErrorCode errorCode, int offset, int length, Message message) {
    // ignored
  }

  @override
  void reportTypeErrorForNode(
      ErrorCode errorCode, AstNode node, List<Object> arguments) {
    // ignored
  }
}

class PreferMixinFix extends LinterFix {
  final classesToConvert = new Set<Element>();

  PreferMixinFix(EditDartFix dartFix) : super(dartFix);

  @override
  Future<void> applyFix() async {
    for (Element elem in classesToConvert) {
      await convertClassToMixin(elem);
    }
  }

  Future<void> convertClassToMixin(Element elem) async {
    AnalysisResult result =
        await dartFix.server.getAnalysisResult(elem.source?.fullName);

    for (CompilationUnitMember declaration in result.unit.declarations) {
      if (declaration is ClassOrMixinDeclaration &&
          declaration.name.name == elem.name) {
        AssistProcessor processor = new AssistProcessor(
            new EditDartFixAssistContext(
                dartFix, elem.source, result.unit, declaration.name));
        List<Assist> assists = await processor
            .computeAssist(DartAssistKind.CONVERT_CLASS_TO_MIXIN);
        final location = dartFix.locationDescription(result, elem.nameOffset);
        if (assists.isNotEmpty) {
          for (Assist assist in assists) {
            dartFix.addFix(
                'Convert ${elem.displayName} to a mixin in $location',
                assist.change);
          }
        } else {
          // TODO(danrubel): If assists is empty, then determine why
          // assist could not be performed and report that in the description.
          dartFix.addRecommendation(
              'Could not convert ${elem.displayName} to a mixin'
              ' because the class contains a constructor in $location');
        }
      }
    }
  }

  @override
  void reportErrorForNode(ErrorCode errorCode, AstNode node,
      [List<Object> arguments]) {
    TypeName type = node;
    Element element = type.name.staticElement;
    String filePath = element.source?.fullName;
    if (filePath != null && dartFix.isIncluded(filePath)) {
      classesToConvert.add(element);
    }
  }
}
