// Copyright (c) 2017, 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:math' as math;

import 'package:status_file/canonical_status_file.dart';

class LintingError {
  final int lineNumber;
  final String message;
  LintingError(this.lineNumber, this.message);

  @override
  String toString() {
    return "Error at line $lineNumber: $message";
  }
}

/// Main function to check a status file for linting errors.
List<LintingError> lint(StatusFile file, {checkForDisjunctions = false}) {
  var errors = <LintingError>[];
  for (var section in file.sections) {
    errors
      ..addAll(lintCommentLinesInSection(section))
      ..addAll(lintAlphabeticalOrderingOfPaths(section))
      ..addAll(lintNormalizedSection(section))
      ..addAll(lintSectionEntryDuplicates(section));
    if (checkForDisjunctions) {
      errors.addAll(lintDisjunctionsInHeader(section));
    }
  }
  errors.addAll(lintSectionHeaderOrdering(file.sections));
  errors.addAll(lintSectionHeaderDuplicates(file.sections));
  return errors;
}

/// Checks for invalid comment lines in a section.
///
/// We do not allow the following:
///
/// [ ... ]
///
/// vm/test: Skip # description
/// # Some comment <-- invalid
/// ...
///
/// This function checks for such invalid comments.
Iterable<LintingError> lintCommentLinesInSection(StatusSection section) {
  if (section.lineNumber == -1) {
    // This is the default section, which also has the dart copyright notice.
    // Allow comment entries in the beginning of the file, until the first
    // status entry.
    var seenStatusEntry = false;
    var lintingErrors = <LintingError>[];
    for (var entry in section.entries) {
      seenStatusEntry = seenStatusEntry || entry is StatusEntry;
      if (seenStatusEntry && entry is CommentEntry) {
        lintingErrors.add(
            LintingError(entry.lineNumber, "Comment is on a line by itself."));
      }
    }
    return lintingErrors;
  }
  return section.entries.whereType<CommentEntry>().map((entry) =>
      LintingError(entry.lineNumber, "Comment is on a line by itself."));
}

/// Checks for disjunctions in headers. Disjunctions should be separated out.
///
/// Example:
/// [ $mode == debug || $mode == release ]
///
/// should not be allowed. The clauses should be refactored into own sections:
/// [ $mode == debug ]
/// ...
///
///
/// [ $mode == release ]
/// ...
///
/// Removing disjunctions will turn some sections into two or more sections with
/// the same status entries, but these will be much easier to process with our
/// tools.
Iterable<LintingError> lintDisjunctionsInHeader(StatusSection section) {
  if (section.condition.toString().contains("||")) {
    return [
      LintingError(
          section.lineNumber,
          "Expression contains '||'. Please split the expression into multiple "
          "separate sections.")
    ];
  }
  return [];
}

/// Checks for correct ordering of test entries in sections. They should be
/// ordered alphabetically.
Iterable<LintingError> lintAlphabeticalOrderingOfPaths(StatusSection section) {
  var entries = section.entries
      .whereType<StatusEntry>()
      .map((entry) => entry.path)
      .toList();
  var sortedList = entries.toList()..sort((a, b) => a.compareTo(b));
  var witness = _findNotEqualWitness<String>(sortedList, entries);
  if (witness != null) {
    return [
      LintingError(
          section.lineNumber,
          "Test paths are not alphabetically ordered in section. "
          "${witness.first} should come before ${witness.second}.")
    ];
  }
  return [];
}

/// Checks that each section expression have been normalized.
Iterable<LintingError> lintNormalizedSection(StatusSection section) {
  var nonNormalized = section.condition.toString();
  var normalized = section.condition.normalize().toString();
  if (nonNormalized != normalized) {
    return [
      LintingError(
          section.lineNumber,
          "Condition expression should be '$normalized' "
          "but was '$nonNormalized'.")
    ];
  }
  return const [];
}

/// Checks for duplicate section entries in the body of a section.
Iterable<LintingError> lintSectionEntryDuplicates(StatusSection section) {
  var errors = <LintingError>[];
  List<StatusEntry> statusEntries =
      section.entries.whereType<StatusEntry>().toList();
  for (var i = 0; i < statusEntries.length; i++) {
    var entry = statusEntries[i];
    for (var j = i + 1; j < statusEntries.length; j++) {
      var otherEntry = statusEntries[j];
      if (entry.path == otherEntry.path &&
          _findNotEqualWitness(entry.expectations, otherEntry.expectations) ==
              null) {
        errors.add(LintingError(
            section.lineNumber,
            "The status entry "
            "'$entry' is duplicated on lines "
            "${entry.lineNumber} and ${otherEntry.lineNumber}."));
      }
    }
  }
  return errors;
}

/// Checks for incorrect ordering of section headers. Section headers should be
/// alphabetically ordered, except, when negation is used, it should be
/// lexicographically close to the none-negated one, but still come after.
///
/// [ $compiler == dart2js ] < [ $strong ]
/// [ $mode == debug ]       < [ $mode != debug ]
/// [ $strong ]              < [ ! $strong ]
///
/// A larger example could be the following:
///
/// [ $mode != debug ]
/// [ !strong ]
/// [ $mode == debug ]
/// [ strong ]
/// [ $compiler == dart2js ]
///
/// which should should become:
///
/// [ $compiler == dart2js ]
/// [ $mode == debug ]
/// [ $mode != debug ]
/// [ strong ]
/// [ !strong ]
///
Iterable<LintingError> lintSectionHeaderOrdering(List<StatusSection> sections) {
  var unsorted = sections.where((section) => section.lineNumber != -1).toList();
  var sorted = unsorted.toList()
    ..sort((a, b) => a.condition.compareTo(b.condition));
  var witness = _findNotEqualWitness<StatusSection>(sorted, unsorted);
  if (witness != null) {
    return [
      LintingError(
          witness.second!.lineNumber,
          "Section expressions are not correctly ordered in file. "
          "'${witness.first!.condition}' on line ${witness.first!.lineNumber} "
          "should come before '${witness.second!.condition}' at line "
          "${witness.second!.lineNumber}.")
    ];
  }
  return [];
}

/// Checks for duplicate section headers.
Iterable<LintingError> lintSectionHeaderDuplicates(
    List<StatusSection> sections) {
  var errors = <LintingError>[];
  var sorted = sections.toList()
    ..sort((a, b) => a.condition.compareTo(b.condition));
  for (var i = 1; i < sorted.length; i++) {
    var section = sorted[i];
    var previousSection = sorted[i - 1];
    if (section.condition.compareTo(previousSection.condition) == 0) {
      errors.add(LintingError(
          section.lineNumber,
          "The condition "
          "'${section.condition}' is duplicated on lines "
          "${previousSection.lineNumber} and ${section.lineNumber}."));
    }
  }
  return errors;
}

ListNotEqualWitness<T>? _findNotEqualWitness<T>(List<T> first, List<T> second) {
  if (first.isEmpty && second.isEmpty) {
    return null;
  }
  for (var i = 0; i < math.max(first.length, second.length); i++) {
    if (i >= second.length) {
      return ListNotEqualWitness(first[i], null);
    } else if (i >= first.length) {
      return ListNotEqualWitness(null, second[i]);
    } else if (first[i] != second[i]) {
      return ListNotEqualWitness(first[i], second[i]);
    }
  }
  return null;
}

class ListNotEqualWitness<T> {
  final T? first;
  final T? second;
  ListNotEqualWitness(this.first, this.second);
}
