# frozen_string_literal: true

class WebHookEmitter
  REQUEST_TIMEOUT = 20

  def initialize(webhook, webhook_event)
    @webhook = webhook
    @webhook_event = webhook_event
  end

  def emit!(headers:, body:)
    uri = URI(@webhook.payload_url.strip)

    connection_opts = {
      request: {
        write_timeout: REQUEST_TIMEOUT,
        read_timeout: REQUEST_TIMEOUT,
        open_timeout: REQUEST_TIMEOUT,
      },
    }

    headers =
      DiscoursePluginRegistry.apply_modifier(:web_hook_event_headers, headers, body, @webhook_event)

    connection_opts[:ssl] = { verify: false } if !@webhook.verify_certificate

    conn = Faraday.new(nil, connection_opts) { |f| f.adapter FinalDestination::FaradayAdapter }

    start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
    error = nil
    response = nil
    begin
      response = conn.post(uri.to_s, body, headers)
    rescue => e
      error = e
    end
    duration = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) - start
    event_update_args = { headers: MultiJson.dump(headers), duration: duration }
    if response
      event_update_args[:response_headers] = MultiJson.dump(response.headers)
      event_update_args[:response_body] = response.body
      event_update_args[:status] = response.status
    else
      event_update_args[:status] = -1
      if error.is_a?(Faraday::Error) &&
           error.wrapped_exception.is_a?(FinalDestination::SSRFDetector::DisallowedIpError)
        error = I18n.t("webhooks.payload_url.blocked_or_internal")
      end
      event_update_args[:response_headers] = MultiJson.dump(error: error)
    end
    @webhook_event.update!(**event_update_args)
    response
  end
end