# frozen_string_literal: true

module ReleaseTools
  module Security
    module Prepare
      class FixesVerifier
        include ::SemanticLogger::Loggable
        include ::ReleaseTools::Security::IssueHelper

        def initialize
          @client = ReleaseTools::GitlabClient
          @fetcher = ReleaseTools::Security::IssuesFetcher.new(@client)
          @security_fixes = []
        end

        def execute
          security_issues = fetcher.execute

          if security_issues.present?
            logger.info('The patch release includes security fixes. Nothing to do')

            send_slack_notification(:success)
            return
          end

          logger.info("The patch release doesn't include security fixes, notifying Delivery and AppSec release managers")

          notify_release_managers
          notify_appsec_release_managers
          send_slack_notification(:success)
        rescue StandardError => ex
          logger.fatal(failure_message, error: ex)

          send_slack_notification(:failed)

          raise
        end

        private

        attr_reader :client, :fetcher, :security_fixes

        def notify_release_managers
          message = <<~MSG.strip
            #{usernames(release_managers.active_release_managers)} :wave:,

            There are no security fixes available for the patch release. This might be caused due to a global holiday period.

            Review if security fixes were recently unlinked from the [security tracking issue](#{security_tracking_issue.web_url}),
            ping the authors to notify them about the patch release due date.

            If necessary, consider delaying the patch release to the next day (Thursday).

            If there are no security fixes available:
            1. Notify AppSec about this.
            2. Perform the patch release with only bug fixes.
          MSG

          create_issue_note(ReleaseTools::Project::Release::Tasks, security_task_issue, message)
        end

        def notify_appsec_release_managers
          message = <<~MSG.strip
            #{usernames(release_managers.active_appsec_release_managers)} :wave:,

            This patch release doesn't include security fixes, please coordinate with release managers.

            If there are no security fixes available, notify the Marketing team that
            no email alert should be sent - #{security_communication_issue.web_url}.
          MSG

          create_issue_note(ReleaseTools::Project::GitlabEe, security_tracking_issue, message)
        end

        def create_issue_note(project, issue, body)
          logger.info('Posting note', project: project.path, issue: issue.web_url, body: body)

          return if SharedStatus.dry_run?

          Retriable.with_context(:api) do
            client.create_issue_note(project, issue: issue, body: body)
          end
        end

        def usernames(users)
          users.map do |user|
            "@#{user.username}"
          end.join(', ')
        end

        def release_managers
          @release_managers ||= ReleaseTools::ReleaseManagers::Schedule.new
        end

        def send_slack_notification(status)
          ReleaseTools::Slack::ReleaseJobEndNotifier.new(
            job_type: 'Security fixes verifier',
            status: status,
            release_type: :patch
          ).send_notification
        end

        def failure_message
          <<~MSG.strip
            Security fixes could not be verified. Review if there are any security fixes on the
            [tracking issue](#{security_tracking_issue.web_url}). If no security issues are present:

            * Notify AppSec that no security fixes are present on the patch release
            * Perform the patch release with only bug fixes.
          MSG
        end
      end
    end
  end
end
