# frozen_string_literal: true

module Danger
  # Plugin for checking tracks-related changes and providing instructions in the PR if that's the case.
  #
  # @example Checking Tracks changes with default settings:
  #          tracks_checker.check_tracks_changes
  #
  # @example Checking Tracks changes with custom Tracks-related files and usage matchers:
  #          tracks_files = ['AnalyticsTracking.swift', 'AnalyticsHelper.swift']
  #          usage_matchers = [/AnalyticsHelper\.sendEvent/]
  #          tracks_checker.check_tracks_changes(tracks_files: tracks_files, tracks_usage_matchers: usage_matchers)
  #
  # @see Automattic/dangermattic
  # @tags github, pull request, tracks, process
  #
  class TracksChecker < Plugin
    TRACKS_PR_INSTRUCTIONS = <<~MESSAGE
      This PR contains changes to Tracks-related logic. Please ensure (**author and reviewer**) the following are completed:

      - The tracks events must be validated in the Tracks system.
      - Verify the internal Tracks spreadsheet has also been updated.
      - Please consider registering any new events.
    MESSAGE

    TRACKS_NO_LABEL_INSTRUCTION_FORMAT = "- The PR must be assigned the **%s** label.\n"
    TRACKS_NO_LABEL_MESSAGE_FORMAT = 'Please ensure the PR has the `%s` label.'

    # Checks the PR diff for changes in Tracks-related files and provides instructions if changes are detected
    #
    # @param tracks_files [Array<String>] List of Tracks-related file names to check
    # @param tracks_usage_matchers [Array<Regexp>] List of regular expressions representing tracks usages to match the diff lines
    # @param tracks_label [String] A label the check should validate the PR against
    # @return [void]
    def check_tracks_changes(tracks_files:, tracks_usage_matchers:, tracks_label:)
      return unless changes_tracks_files?(tracks_files: tracks_files) || diff_has_tracks_changes?(tracks_usage_matchers: tracks_usage_matchers)

      tracks_message = TRACKS_PR_INSTRUCTIONS

      unless tracks_label.nil? || tracks_label.empty?
        tracks_message += format(TRACKS_NO_LABEL_INSTRUCTION_FORMAT, tracks_label)

        labels_checker.check(
          do_not_merge_labels: [],
          required_labels: [/#{Regexp.escape(tracks_label)}/],
          required_labels_error: format(TRACKS_NO_LABEL_MESSAGE_FORMAT, tracks_label)
        )
      end

      # Tracks-related changes detected: publishing instructions
      message(tracks_message)
    end

    private

    def changes_tracks_files?(tracks_files:)
      git_utils.all_changed_files.any? do |file|
        tracks_files.any? { |tracks_file| File.basename(file) == File.basename(tracks_file) }
      end
    end

    def diff_has_tracks_changes?(tracks_usage_matchers:)
      matched_lines = git_utils.matching_lines_in_diff_files(
        files: git_utils.all_changed_files,
        line_matcher: ->(line) { tracks_usage_matchers.any? { |tracks_usage_match| line.match(tracks_usage_match) } },
        change_type: nil
      )

      !matched_lines.empty?
    end
  end
end